DS博客作业02--线性表
0.PTA总分
- 线性表
1.本周学习总结
1.1 总结线性表内容
顺序表
- 顺序表结构体定义
顺序表包括元素跟顺序表的长度,元素用数组存放
typedef struct
{
int data[Size]; //存放顺序表元素
int length ; //存放顺序表的长度
} List;
typedef List *SqList; //指针
- 顺序表插入
由于元素仍用数组储存,所有插入数据时移动数组时必不可免的,但仍需注意的时每次插入完,顺序表长度(lenth)需加1
for (i = 0; i < L->length; i++) //遍历顺序表
{
if (L->data[i] >= x) //找到要插入的位置
{
for (k = L->length; k > i; k--)
{
L->data[k] = L->data[k - 1]; //将该位置往后所有元素右移一位
}
L->data[i] = x; //插入元素
break;
}
else if (x >= L->data[L->length]) //如果在顺序表尾,则直接添加,无需移动
{
L->data[L->length] = x;
}
}
L->length += 1; //注意每次插入顺序表长度加1
- 顺序表的删除
在删除时,其本质跟插入差不了多少,只不过一个右移一个左移,注意顺序表长度减1
for (i = 0; i < L->length; i++) //遍历顺序表
{
if (L->data[i] == x) //找到要删除的位置
{
for (k = i; k <L->length; k++)
{
L->data[k] = L->data[k + 1]; //将该位置往后所有元素左移一位,覆盖原位置元素
}
L->length -= 1; //顺序表长度减1
}
}
链表
- 链表结构体定义
链表结构体包括所储存的元素以及指向下一结点的指针
typedef struct LNode //定义单链表结点类型
{
ElemType data;
struct LNode *next; //指向后继结点
} LNode,*LinkList;
- 链表 头插法
每次插入的数据均在头结点下一位,这样使得输入跟输出的顺序截然相反。
void CreateListF(LinkList& L, int n)//头插法建链表,L表示带头结点链表,n表示数据元素个数
{
L = new LNode;
L->next = NULL; //开辟头结点
LinkList head, p, pre;
head = L;
int i;
for (i = 0; i < n; i++)
{
p = new LNode;
cin >> p->data;
p->next = head->next;
head->next = p;
}
}
-
链表 插入、删除
链表中插入输出操作相对于数组而言简单不少,无需任何的移动,仅需改变链的关系即可。插入
while (pre->next) //由于插入时需要知道插入位置的前驱,所有采用pre—>next为循环变量。
{
if (pre->next->data >= e)
{
p->next = pre->next; //改变链的关系
pre->next = p;
break;
}
pre = pre->next;
}
删除
while (pre->next) //删除时需要知道删除位置的前驱,采用pre—>next为循环变量。
{
if (pre->next->data == e)
{
p = pre->next; //保留删除节点
pre->next = p->next; //改变链的关系
free(p); //释放所要删除节点
break;
}
pre = pre->next;
}
有序表
- 有序单链表数据插入、删除
其操作的思路及核心代码跟普通链表的插入删除没有区别,只不过需判断特殊情况
插入
while (pre->next)
{
if (pre->next->data >= e)
{
p->next = pre->next;
pre->next = p;
flag = 0; //标记状态 说明已经找到位置并完成插入
break;
}
pre = pre->next;
}
if (flag == 1)pre->next = p; //若还没找到插入位置 说明插入位置在链尾,做单独处理
删除
while (pre->next)
{
if (pre->next->data == e)
{
p = pre->next;
pre->next = p->next;
free(p);
flag = 0; //标记状态 说明找到删除位置
break;
}
head = head->next;
}
if (flag == 1)cout << e << "找不到!" << endl; //若没找到 输出相应提示
- 有序单链表表合并
同时遍历两链表,并比较数据大小,将较小的采用头插法插入另一条链。
while (L1->next&&L2->next)
{
if (L1->next->data > L2->next->data) //当L2数据小于L1时,采用头插法插入
{
p = new LNode;
p->data = L2->next->data;
p->next = L1->next;
L1->next = p;
L2 = L2->next;
}
else if(L1->next->data == L2->next->data)L2 = L2->next; //如果两数据相等则跳过
L1 = L1->next;
}
if (L1->next == NULL)L1->next = L2->next; //当L1遍历完,将L1尾部接上L2剩下的数据。
- 循环单链表
类似于一个圈,任意一个节点均能访问整条链
//带头结点为L
while(pre->next!=L)
//不带头节点
while(p!=L)
- 双链表
即有两个方向的两边,一个节点既有前驱指针,也有后驱指针
定义
typedef struct node
{
int data;
struct node* pre; //指向前一节点的指针
struct node* next; //指向后一节点的指针
}DLNode, *DLinkList;
- 循环双链表
即在双链表的基础上围成一个圈
(就不画图了)
1.2 线性表的认识及学习体会。
由于线性表内容中大部分知识点在上学期C的学习中已经接触了不少,所以对于线性表的学习即操作中并没有较大的障碍。刚接触时一些较新的知识点,会出现一脸懵的状态,比如头插法,单链表逆置等,还是花了一定的时间去理解消化并准备活用。总而我觉得线性表比较灵活,需要较好的掌握它。
2.PTA实验作业
2.1 6-2 jmu-ds-有序表插入数据
2.1.1 代码截图
2.1.2本题PTA提交列表说明
1.部分正确:考虑过于简单,只写了插入数据位于两数之间的代码,情况并没有考虑,导致较多错误。随后补上了插入在头和在尾的代码。
2.部分正确:忘记考虑表空情况。加上了判空代码,也就相对完整了。
3.全部正确。
2.2 6-9 jmu-ds-有序链表合并
2.2.1 代码截图
2.2.2本题PTA提交列表说明
1.部分正确:代码思路有问题,我采用每次判断一对数字,插入玩均往下走。导致会出现输入1 1 ,2 2 输出1 2 1 2的情况。后来更改为一旦L2数据小于L1就采用头插法插入L1。
2.部分正确:由于细节问题,L2插入完忘记往下走。随后补上代码。
3.部分正确:没有看清题目具体要求,即:“合并后需要去除重复元素”。加上若两数相等,则L2继续下走。
4.全部正确。
2.3 6-10 jmu-ds-有序链表的插入删除
2.3.1 代码截图
2.3.2本题PTA提交列表说明
1.大部分段错误:为了找到错误具体在哪一部分而提交的。
2.运行超时:同上。
3.段错误:删除函数中,进行一次删除后我仍使指针后移并且在外层仍有一个指针后移代码,这导致一次移动2个位置,出现段错误。后在插入代码中加入break。
4.答案错误:修正段错误代码后忘记添上删除部分代码,直接提交导致错误。
5.部分正确:链表全删时,输出重复。因为链表为空时进不了循环就没注意,然而函数中仍会输出“找不到”。随后加上链表为空直接返回的代码。
6.全部正确。
3.1 1.6判断一个单链表中是否有环
3.1.1 该题的设计思路
3.1.2 该题的伪代码
定义两个快,慢指针fast,slow;
while(fast != NULL && fast->next != NULL)
{
slow每次后移一位;
fast每次后移2位;
if (fast==slow)//说明两者相遇
return true;
}
end while
return false;
//当fast或fast->next移动到NULL时,或链表为空或只有一个元素时。不符合,返回false。
本题时间复杂度O(n);空间复杂度O(1)
3.1.3 运行结果
先简单的通过手动改代码实现带环
3.1.4分析该题目解题优势及难点。
- 采用快慢指针操作,觉得比较新颖,所以摘抄此题目为例题。其类似借鉴于数学中的追及相遇问题,速度不同两者绕环跑时必然会相遇。借此编写代码十分巧妙
- 循环条件不能遗漏'fast->next != NULL',否则可能会出现访问非法内存错误。我觉得这是一个注意点。
3.2 相交链表(LeetCode160题)
3.2.1 该题的设计思路
3.2.2 该题的伪代码
定义两条链L1,L2
while (L1)
{
计算L1长度lenthA;
}end while
while (L2)
{
计算L2长度lenthB;
}end while
计算长度差size=fabs(lenthA-lenthB);
长的链先走size个节点;
while(L1&&L2)//同时同速遍历两链表
{
if 两链中节点相同
return 相同元素节点
}end while
return NULL;
本题时间复杂度O(1)空间复杂度O(n)
3.2.3 运行结果
其中我自建一个链表,分别加在L1,L2的尾部使它们有公共节点。输入的为L1,L2,输出为第一个相同节点的数据。
3.2.4分析该题目解题优势及难点。
- 先做长度处理,使其类似进行尾部对齐,从较短链开始同时同速遍历,无需嵌套循环。
- 比较时,注意比较的是节点,而不是数据。这是两个截然不同的东西。