线性表
线性表定义
- 线性表是具有相同数据类型的 n n n 个数据元素的有限序列,其中 n n n 为表长。当 n = 0 n=0 n=0 时线性表是一个空表。
- 若用 L L L 命名线性表,表示为: L = ( a 1 , a 2 , a i , a i + 1 , . . . , a n ) L=(a_1, a_2, a_i, a_{i+1}, ... , a_n) L=(a1,a2,ai,ai+1,...,an)
- a 1 a_1 a1 是第一个元素,称为=="表头元素"==;
- a n a_n an 是最后一个元素,称为=="表尾元素"==;
- 除第一个元素外,每个元素有且只有一个直接前驱;
- 除最后一个元素外,每个元素有且只有一个直接后继。
- 线性表的逻辑具有顺序性,表中元素有其先后次序。
- 线性表的数据类型都相同,每个元素占有相同大小的存储空间。
线性表基本操作
线性表的主要操作如下:
c
InitList(&L) // 初始化表,构造一个空的线性表
Length(L) // 求表长,返回线性表L的长度,即线性表中元素个数
LocateElem(L,e) // 按值查找操作,在表L中查找值e
GetElem(L,i) // 按位查找操作,获取表L中第i个位置的元素的值
ListInsert(&L,i,e) // 插入操作,在表L中的第i个位置插入指定元素e
ListDelete(&L,i,&e) // 删除操作,删除表L中第i个位置元素并用e返回删除元素的值
PrintList(L) // 输出操作,按前后顺序输出线性表L的所有元素的值
Empty(L) // 判空操作,若L为空表返回True,否则False
DestoryList(&L) // 销毁操作,销毁线性表,并释放线性表L占用的内存空间
线性表的物理表示
- 顺序表,逻辑上相邻的两个元素在物理位置上也相邻;
- 链式表示,通过"链"建立起数据元素之间的逻辑关系。
顺序表
- 线性表的顺序表示,逻辑上相邻的两个元素在物理位置上也相邻;
- 顺序表的任一元素的存取时间复杂度为 O ( 1 ) O(1) O(1);
- 顺序表的插入、删除操作所需时间复杂度为 O ( n ) O(n) O(n),因为要保证物理位置的相邻,所以插入和删除都需要移动大量元素,时间也都耗费在移动中;
- 顺序表详细博文链接:https://xu-hongduo.blog.csdn.net/article/details/133883937
单链表
- 单链表无需顺序表那样必须占用相邻的物理空间存储,而是采用链的方式连接;
- 单链表的任一元素的存取时间复杂度为 O ( 1 ) O(1) O(1);
- 单链表的插入、删除操作所需时间复杂度为 O ( n ) O(n) O(n),因为物理位置不相邻,所以要耗费时间遍历查找要删除、插入元素的前驱元素。
- 单链表详细博文链接:https://xu-hongduo.blog.csdn.net/article/details/133884286
双链表
- 双链表在单链表的基础上,在每个元素上都加入第二个指针,前驱指针。如此以来,在得知待插入和删除元素的物理地址时,插入和删除操作的时间复杂度降低为 O ( 1 ) O(1) O(1),因为无需再耗费时间再次从头遍历来查找要删除、插入元素的前驱元素。
- 双链表详细博文链接:https://xu-hongduo.blog.csdn.net/article/details/133885829
循环链表
- 循环链表分为循环单链表以及循环双链表;
循环单链表:
- 循环单链表中最后一个结点的指针不是 NULL,而改为指向头结点。从而整个链表形成一个环。
- 循环单链表判空的条件为表尾结点指针是否指向头结点;
- 循环单链表因为是一个"环",所以在任何一个位置上的插入和删除操作都是等价的,循环单链表可以从表中的任意一个结点开始遍历整个列表。
循环双链表:
- 循环双链表中,头结点的 p r i o r prior prior 指针指向表尾结点,尾结点的 n e x t next next 指针指向头结点。
- 在循环双链表 L L L 中,某结点 ∗ p *p ∗p 为尾结点时,p->next==L;当循环双链表为空表时,其头结点的 p r i o r prior prior 域和 n e x t next next 域都等于 L L L;
静态链表
-
静态链表借助数组来描述线性表的链式存储结构,结点也有数据域 d a t a data data 和指针域 n e x t next next。而与单链表不同的是,这里的指针是结点的相对地址。所谓相对地址请读者联系下张图理解;
-
其中 a a a 的直接后继为 b b b,所以在表 "静态链表示例" 中, a a a 的直接后继的物理地址为 1 1 1,查找表中代表的物理地址为 1 1 1 的元素,为 b b b。
c
#define MaxSize 50 // 静态链表最大长度
typedef struct{ // 静态链表结构类型的定义
ElemType data; // 存储数据元素
int next; // 下一个元素的数组下标
}SLinkList[MaxSize];
- 静态链表以 n e x t = = − 1 next==-1 next==−1 作为其结束的标志。静态链表的插入、删除操作与动态链表相同,只需要修改指针而无需移动元素。
- 总而言之,静态链表没有单链表使用起来方便,但是在一些不支持指针的高级语言中,这是一种非常巧妙的设计方法。
顺序表与链表的比较
存取方式
- 顺序表:可以顺序存取、也可随机存取;因为顺序表逻辑上相邻的元素物理地址上也相邻;
- 链表:只能从表头顺序存取元素,因为链表不具有物理地址的连续性。无论是单链表还是双链表;
逻辑结构与物理结构
- 顺序存储:逻辑结构上相邻的元素,物理存储位置也相邻;
- 链式存储:逻辑上相邻的元素,物理存储位置不一定相邻,对应的逻辑关系通过链接来实现;
查找、插入与删除
- 顺序表:按值查找 O ( n ) O(n) O(n),按序号查找 O ( 1 ) O(1) O(1),插入删除 O ( n ) O(n) O(n);
- 链表:皆为 O ( n ) O(n) O(n);
空间分配
- 顺序表:静态存储下存储空间满溢出,动态存储下,另外开辟新的连续空间,需要移动大量元素,对空间比较浪费;
- 链表:有地方就能塞,灵活高效;
怎样选取存储结构
基于存储
当线性表的长度难以估计时,不宜采取顺序表;反之;
基于运算
如果经常做的运算是按序号访问数据元素,无疑顺序表优于链表;
在进行插入、删除操作时,平均移动表中一半的元素。当数据元素的信息量较大时,应考虑链表优先。虽然链表也需要找插入位置,但是其主要操作是对比,而不是移动。
基于环境
显而易见的是,顺序表的结构设计上明显更为实现起来较链表更为简单。
总而言之,较稳定的线性表选择顺序表,涉及频繁操作的选择链式存储。
--
以上