数据结构学习(五)——线性表
参考文献:
[1]王道论坛.2018年数据结构考研复习指导 [M]北京:电子工业出版社,2017.03
[2]吴伟民,李小妹,刘添添,黄剑锋,苏庆,林志毅,李杨.数据结构(校内教材修订版) 广东工业大学计算机学院,2015.6
目录:
1、简单笔记:
2、顺序表删除最小值:
3、单链表就地逆置:
4、将单链表中元素排序:
5、找出两个单链表公共结点:
6、就地拆分线性表:
7、两个单链表进行归并后排序:
8、求两个递增排列的链表的相同的结点的值的集合:
9、求一个单链表是否为另一个单链表的连续子序列:
10、链表结点添加访问频度并将结点按频度排序:
1、简单笔记:
(1)线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列。除表头元素外,每个元素有且仅有一个直接前驱。除表尾元素外,每个元素有且仅有一个直接后继。
(2)线性表中元素的位序是从1开始的,而数组中元素的下标是从0开始的。
(3)顺序表的特点是表中元素的逻辑顺序与其物理顺序相同。
(4)头指针和头结点的区别:
①不管带不带头结点,头指针始终指向链表的第一个结点,而头结点是带头结点链表中的第一个结点,结点内通常不存储信息。
②引入头结点后的好处:
a)由于开始结点的位置被存放在头结点的指针域中,所以在链表的第一个位置上的操作和在表的其他位置上的操作一致,无须进行特殊处理。
b)无论链表是否为空,其头指针是指向头结点的非空指针(空表中头结点的指针域为空),因此空表和非空表的处理也统一了。
(5)循环单链表的判空条件不是头结点的指针是否为空,而是它是否等于头指针。
(6)循环双链表中,某结点*p为尾结点时,p->next==L,当循环双链表为空表时,其头结点的prior域和next域都等于L。
(7)静态链表是借助数组来描述线性表的链式存储结构,结点也有数据域data和指针域next,其中指针是结点的相对地址(数组下标),又称为游标。和顺序表一样,静态链表也要预先分配一块连续的存储空间。静态链表以next==-1作为其结束的标志。
#define MaxSize 80
typedef struct{
ElemType data;
int next;
}SLinkList[MaxSize];
2、从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删元素的值。空出的位置由最后一个元素填补,若顺序表为空则显示出错信息并退出运行。
思路:①判空,为空return,不为空继续②
②将顺序表中第一个元素的值赋值给min
③遍历顺序表,若元素值比min小,则将该元素值赋值给min
④若最小的是最后一个元素或该顺序表一共只有一个元素,将0赋值给该位置的元素,并返回被删元素值。
3、编写算法将带头结点的单链表就地逆置,所谓“就地”是指辅助空间复杂度为O(1)。
思路:将头结点摘下,然后从第一结点开始,依次向前插入到头结点的后面,直到最后一个结点为止,则实现了链表的逆置。
图3.1 代码示例
4、有一个带头结点的单链表L,设计一个算法使其元素递增有序。
思路:构造只有一个数据结点的有序单链表,然后依次扫描单链表中剩下的结点*p,直到为NULL为止,在有序表中通过比较查找插入*p的前驱结点*pre,然后将*p插入到*pre之后。
图4.1 代码示例
5、给定两个单链表,设计算法找出两个链表的公共结点。
思路:如果两个链表有一个公共结点,那么该公共结点之后的所有结点都是重合的,即它们的最后一个结点必然是重合的。因此,判断两个链表是不是有重合的部分,只要分别遍历两个链表到最后一个结点。如果两个尾结点是一样的,说明它们有公共结点,否则两个链表没有公共的结点。
所以先分别遍历两个链表得到它们的长度,并求出两个长度之差。在长的链表上限遍历长度之差个结点后,再同步遍历两个链表,直到找到相同的结点,或者一直到链表结束。此时,时间复杂度为O(len1+len2)。
图5.1 代码示例
6、设C={a1,b1,a2,b2,…an,bn}为线性表,采用带头结点的hc单链表存放,设计一个就地算法,将其拆分为两个线性表,使得A={a1,a2,…,an},B={bn,…,b2,b1}。
思路:将单链表构造B时使用头插法。
图6.1 代码示例
7、假设有两个按元素值递增次序排列的线性表,均以单链表形式存储。设计算法将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表。
思路:使用头插法
图7.1 代码示例
8、已知两个链表A和B分别表示两个集合,其元素递增排列。设计算法,求A与B的交集,并存放于A链表中。
思路:采用归并的思想,设置两个工作指针pa和pb,对两个链表进行归并扫描,只有同时出现在两集合中的元素才连接到结果表中且仅保留一个,其他的结点全部释放。当一个链表遍历完成后,释放另一个表中剩下的全部结点。
图8.1 代码示例
9、两个整数序列A=a1,a2,a3,…,am和B=b1,b2,b3,…,bn已经存入两个单链表中,设计算法,判断序列B是否是序列A的连续子序列。
思路:如果B是A的连续子序列,则从A开始遍历,当遍历到与B的第一个元素相等的结点时,则继续查看第二个元素,直到B中的元素遍历完都与A匹配,则可以证明B是序列A的连续子序列。
图9.1 代码示例
10、设头指针为L的带有头结点的非循环双向链表,其每个结点中除有pred(前驱指针)、data(数据)和next(后继指针)域外,还有一个访问频度域freq。在链表被启用前,其值均初始化为零。每当在链表中进行一次Locate(L,x)的运算时,令元素值为x的结点中freq域的值增1,并使此链表中结点保持按访问频度非增(递减)的顺序排列,同时最近访问的结点排在频度相同的结点的前面,以便使频繁访问的结点总是靠近表头。设计算法Locate(L,x),该运算为函数过程,返回找到结点的地址,类型为指针型。
思路:先查找到该结点,取出来,然后沿着前驱结点向前找到第一个频度比它大的结点,插入到该结点之后。
图10.1 代码示例