0.PTA得分截图
1.本周学习总结(0-4分)
1.1 总结线性表内容
顺序表(线性表(List):零个或多个数据元素的有限序列)
+顺序表结构体定义
typedef int Status
typedef int ElemType;
typedef Struct
{
ElemType data[MAXSIZE]; /*数组存储数据元素*/
int length; /*线性表当前长度*/
}SqList;
ADT 线性表 (List)
Data
Operation
lnitList(*L);//初始化操作,建立一个空的线性表
CreateList(L,n);//创建线性表,输入数据保证是有序的
InsertSq(SqList *&L,int x):顺序表L中插入数据x。
void DelSameNode(List &L) ;//删除顺序表重复元素
DelNode(L,min,max);//删除区间元素
DispList( L);//输出线性表
DestroyList(L);//销毁线性表,
endADT
线性表的基本操作
1.初始化线性表
void lnitList(SqList& L)
{
if (线性表为空)
返回;
L->length=0;//线性表初始化
}
2.插入数据
void InsertSq(SqList& L, int x)
{
int i, j;
for (i=0 to L->length-1 and x > L->data[i]; i++);//循环查找插入点
for (j = L->length to i ; j--)
{
j+1位置的数据写入j位置数据
}
位置i下插入数据x;
表长增长 1 ;
}
3.删除重复数据
void DelSameNode(List& L)//删除顺序表重复元素
{
if (表为空) return;
int i, j, k;
for (i = 0 to L->length - 2; i++)
{
for (j = i + 1 to L->length-1; j++)
{
if (j位置数据是否等于i位置数据)
{
等于:删除j位置数据;
L->length--;
不等:无
}
}
}
4.删除操作
// 删除位置不合理,抛出异常
// 取出删除的元素
// 从删除元素位置开始遍历到最后一个元素的位置
// 分别将他们向前移动一个位置
// 表长减一
bool ListDelete(SqList& L,int i,ElemType& e)
{
int k;
if (L->length==0)return false; //线性表为空
if (i<1 || i>L->length)return false; //当i不在范围
*e=L->data[i-1];
if (1length) //当i不在表尾
{
for (k=i; klength; k++)
{
L->data[K-1]=L->data[k];
}
}
L->length--; //表长减一
return true;
}
补充: 区间数据的删除
// 不属于删除区间数据重新写入
// 在区间内元素不写入
// 修改表长
bool ListDelete(SqList& L,int min,int max)
{
int k , j;
if (L->length==0)return false; //线性表为空
for (k=0,j=0; k < L->length; i++)
{
if (L->data[k]data[k]>max)
{
L->data[j++] = L->data[k];
}
}
L->length = j;
return true;
}
线性表的顺序存储结构的优缺点和特点
优点:无须为表示表中元素之间的逻辑关系为增加额外的存储空间
可以快速地存取表中任一位置的元素
缺点: 插入和删除操作需要移动大量元素
当线性表长度变化较大时,难以确定空间的容量
造成存储空间的“碎片”
2.线性表的链式存储结构--链表
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的
逻辑顺序是通过链表中的指针链接次序实现的。
链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在
运行时动态生成。每个结点包括两个部分:存储数据元素的数据域,
存储下一个结点地址的指针域。
链表结构体定义
typedef int ElemType;
typedef struct LNode //定义单链表结点类型
{
ElemType data; //数据
struct LNode *next; //指向后继结点
} LNode,*LinkList;
ADT 链表(Link)
Data
Operation
endADT
头插法
生成新节点插入到头节点后面
代码:
void CreateListF(LinkList& L, int n)//头插法建链表,L表示带头结点链表,n表示数据元素个数
{
L = new struct LNode;
L->next = NULL;
LinkList node;
for (int i = 0; i > node->data;
node->next = L->next;
L->next = node;
}
}
尾插法
生成新节点插入到尾指针后面,尾指针后移
代码:
void CreateListR(LinkList& L, int n)//尾插法建链
{
LinkList tail, node;
L = new LNode;
L->next = NULL;//初始化链表
tail = L;
for (int i = 0; i < n; i++)
{
node = new LNode;
cin >> node->data;
node->next = NULL;
tail->next = node;
tail = tail->next;
}
}
链表插入
pre,p由于遍历查找插入位点,并插入
代码:
void ListInsert(LinkList& L, ElemType e,int i)
{
LinkList pre;
LinkList node;
for (pre = L;i != 0;pre = pre->next)
{
i--;
}
node = new LNode;
node->data = e;
node->next = pre->next;
pre->next = node;
}
删除操作
pre,p用于遍历查找需要删除结点
代码:
void ListDelete(LinkList& L, ElemType e)//链表删除元素e
{
LinkList p;
p = new LNode;
p = L;
if (p->next == NULL)
{
return;
}
while (1)
{
if (p != NULL && p->next != NULL)
{
if (e == p->next->data)
{
p->next = p->next->next;
return;
}
}
if (p == NULL)
{
break;
}
p = p->next;
}
cout << e << "找不到!" << endl;
}
有序表合并
pre, p分别用于遍历Link1, Link2
两个指针同时向前进行遍历链表
移动小数据结点,保留大数据结点
修改L1指向链
代码:
void MergeList(LinkList& L1, LinkList L2)//合并链表
{
LinkList L3;
LinkList p;
LinkList q;
LinkList temp;
LinkList s;
s = new LNode;
L3 = s;//给L3建立链表
L3->next = NULL;
p = L1->next;
q = L2->next;
while (p && q)
{
if (p->data < q->data)
{
temp = p;
p = p->next;
temp->next = NULL;
s->next = temp;
s = temp;
}
else if (p->data > q->data)
{
temp = q;
q = q->next;
temp->next = NULL;
s->next = temp;
s = temp;
}
else//数值相等的情况
{
temp = p;
p = p->next;
q = q->next;
temp->next = NULL;
s->next = temp;
s = temp;
}
}
if (p)//while语句循环时间比较长,运行超时,改为if语句
{
s->next = p;
}
if (q)
{
s->next = q;
}
L1 = L3;
}
如图:
循环链表、双链表结构特点
循环链表
循环链表是一个收尾相接的链表,将单链表的最后一个指针域由NULL
改为指向表头结点这就是单链式的循环链表,并称为循环单链表
带头结点的循环单链表的各种操作的算法实现与带头结点单链表的算法实现类似,
差别仅在于算法判别当前结点p是否为尾结点的条件不同。
单链表中的判别条件为p!=NULL或p->next!=NULL,
而单循环链表判别条件是p!=L或p->next!=L
创建单循环链表
void CreatCLLinkList(CLLinkList& CL)
{
Node *rear,*s;
rear=CL;//rear指针动态指向当前表尾,其初始值指向头结点
int flag=1;
int x;
printf("Please input data and enter 0 end:\n");
while(flag)
{
scanf("%d",&x);
if(x!=0)
{
s=(Node *)malloc(len);
s->data=x;
rear->next=s;
rear=s;
}
else
{
flag=0;
rear->next=CL;//最后一个节点的next域指向头结点
}
}
}
---------------我是一条分界线-----------------我是一条分界线-----------------我是一条分界线-----------------我是一条分界线----------------
双向链表
在单向链表的基础上,给各个结点额外配备一个指针变量,用于指向每
个结点的直接前趋元素。这样的链表被称为“双向链表”或者“双链表”。
typedef struct line{
struct line * prior; //指向直接前趋
int data;
struct line * next; //指向直接后继
}Lnode,*LinkList;
尾插法创建双向链表
void initLine(line & L){
L=new Lnode;//创建链表第一个结点(首元结点)
L->prior=NULL;
L->next=NULL;
LinkList tail=L;
LinkList node;
int i;
for (i=2; i<=3; i++) {
//创建并初始化一个新结点
node==new Lnode;
node->prior=NULL;
node->next=NULL;
node->data=i;
tail->next=node;//直接前趋结点的next指针指向新结点
node->prior=tail;//新结点指向直接前趋结点
tail=tail->next;
}
}
上面要求是必须完成,但是完成时候需要根据实际所学再展开。内容简单应付,0分。注意每个知识点务必要举例,图形等说明。
1.2.谈谈你对线性表的认识及学习体会。
对线性表的认识
1.多个具有相同特性的数据元素按照一对一的关系进行排序的有限序列
2.在一条线性表中的数据一定是相同的数据类型
学习体会
问题总结 |
---|
线性表的使用可以很好的加强对数据,内存的应用; |
在使用函数时应该先判断表是否为空; |
重点考虑指针访问时时候会非法访问; |
增强各结点间的有效关系使用。 |
---------------还是我:分界线-----------------还是我:分界线-----------------还是我:分界线-----------------还是我:分界线----------------
2.PTA实验作业(0-2分)
选3道PTA题目,不写伪代码,只贴代码截图,并记录代码提交碰到问题及解决方法。必须选择线性结构应用题目,不得选操作集类似题目,头插法、尾插法、链表逆转也不得选。(选,则为0分)选择难度越高题目得分越高。
2.1.题目:
2.1.1代码截图
2.1.2本题PTA提交列表说明。
提交结果 | 结果说明 |
---|---|
编译错误 | 末尾return指针L->data时使用了中文符号(同学帮忙找出的) |
2.2.题目:有序链表合并
2.2.1代码截图
2.2.2本题PTA提交列表说明。
提交结果 | 结果说明 |
---|---|
部分正确(未考虑空表) | 增加考虑对空表的处理 |
编译错误(没删除前段代码) | 代码重调 |
部分正确(对空表考虑不全) | 空表时修改头结点 |
2.3.题目:一元多项式的乘法与加法运算
2.3.1代码截图
2.3.2本题PTA提交列表说明。
提交结果 | 结果说明 |
---|---|
编译错误 | 选错了对应的编译器 |
3.阅读代码(0--4分)
注意:不能选教师布置在PTA的题目。完成内容如下。
3.1
题目及解题代码
class Solution {
public:
void reorderList(ListNode* head){
helper(head);
}
ListNode* helper(ListNode* head){
if(!head || !(head->next) || !(head->next->next)){return head;}
ListNode* res=head;
ListNode* p =head;
ListNode* next = head->next;
while(p->next){
if(!(p->next->next)){
break;
}
p = p->next;
}
head->next = p->next;
p->next = nullptr;
head = head->next;
head->next = helper(next);
return res;
}
};
3.1.1 该题的设计思路
使用迭代返回,使末结点依次返回重插
3.1.2 该题的伪代码
class Solution {
public:
void reorderList(ListNode* head){
helper(head);
}
ListNode* helper(ListNode* head){
if(如果链表没有空间、为空、只有一个结点){return head;}
ListNode* res=head;
ListNode* p =head;
ListNode* next = head->next;
while(p->next){
if(只剩下一个结点)){
结束;
}
p = p->next;
}
将最后一个指针插入到头节点后面
转到下一个插入点
调用函数
return res;
}
};
3.1.3 运行结果
3.1.4分析该题目解题优势及难点。
·解题优势:
采用最简单的结点插入计算
空间复杂度为O(1),时间复杂度为O(n);