第三章 线性表
最后更新于:2022-04-01 23:02:03
### 一、线性表定义
线性表:零个或多个数据元素的**有限**序列。(零个的时候是空表)
线性表的特性是:除了第一个元素(只有后继)和最后一个元素(只有前驱),每个元素都只有一个前驱和后继。
### 二、线性表的抽象数据类型
线性表的抽象数据类型定义如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368a15c9c.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368a342e3.jpg)
### 三、线性表的顺序存储结构
线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。
来看线性表顺序存储结构代码:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368a5bcb5.jpg)
发现描述顺序存储结构需要三个属性:
1.储存空间的起始位置:数组data,它的存储位置就是存储空间的存储位置。
2.线性表的最大存储容量:数组长度MaxSize。
3.线性表的当前长度:length。
下面再讨论一下地址的计算方法:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368a7bc1b.jpg)
### 四、顺序存储结构的插入与删除
获得元素的操作:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368a9a9b8.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368ab331a.jpg)
插入操作:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368ade4d6.jpg)
删除操作:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368b15c4d.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368b3118c.jpg)
线性表的顺序存储结构的优缺点:
优点:1.无需为表示表中元素之间的逻辑关系而增加额外的存储空间2.可以快速地存取表中任一位置的元素。
缺点:1.插入和删除操作需要移动大量元素2.当线性表长度变化较大时,难以确定存储空间的容量3.造成存储空间的碎片。
### 五、线性表的链式存储结构
n个节点链结成一个链表,即为线性表的链式存储结构,因为此链表的每一个节点中只包含一个指针域,所以叫做单链表。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368b52016.jpg)
把链表中第一个节点的存储位置叫做头指针,最后一个节点指针为空。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368b663c0.jpg)
一般为了方便对链表进行操作,会在单链表的第一个结点前附设一个结点,成为头结点。头结点的**数据域可以不保存任何信息**。
头指针和头结点的异同:
**头指针**是指向头结点的指针;头指针具有标识作用,所以常用头指针冠以链表的名字;无论链表是否为空,头指针均不为空。头指针是链表的必要元素。
**头结点**是为了操作的统一和方便而设立的,放在第一个元素的结点之前,其数据域一般无意义(也可以存放链表的长度);有了头结点,对在第一个元素结点前插入结点和删除第一结点,其操作与其他结点的操作就统一了;头结点不一定是链表的必须元素。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368b800d0.jpg)
结点的概念:结点由存放数据元素的**数据域**存放后继结点的**指针域**组成。
假设P是指向线性表的第i个元素的指针,则该节点aI的数据域我们可以用p->data来表示,p->data的值是一个数据元素,结点aI的指针域可以用p->next来表示,p->next的值是一个指针。如果p->data=ai,那么p->next->data=aI+1。即:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368b93633.jpg)
### 六、单链表的读取
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368ba594e.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368bc75db.jpg)
由上面程序看出来,获取链表获取第i个元素比较麻烦。
### 七、单链表的插入与删除
插入结点:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368bedb79.jpg)
删除结点:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368c1f8c4.jpg)
由算法可以看出,插入和删除对于链表来说每次只需要简单地通过赋值移动指针而已,时间复杂度都是O(1),显然,对于插入和删除数据越频繁的操作,单链表的效率优势就越是明显。
### 八、单链表的整表创建
头插法:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368c41bd5.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368c56c7c.jpg)
尾插法:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368c7dbbb.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368c9b92d.jpg)
### 九、单链表的整表删除
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368cc01aa.jpg)
十、单链表结构与顺序存储结构优缺点
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368ce9584.jpg)
### 十一、循环链表
将单链表的终端结点的指针端由空指针改为指向头结点,就使整个单链表形成了一个环,这种头尾相连的单链表称为单循环链表,简称循环链表。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368d15961.jpg)
下面研究一下循环链表的合并:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368d28052.jpg)
分成4步:
1.p=rearA->next;
2.rearA->next=rearB->next->next;
3.rearB->next=p;
4.free(p).
### 十二、双向链表
双向链表概念:双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368d4075e.jpg)
双向链表插入操作:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368d5a8fb.jpg)
同样也分成4步:
1.s->prior=p;
2.s->next=p->next;
3.p->next->prior=s;
4.p->next=s.
双向链表的删除操作:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368d6bf4b.jpg)
分成3步:
1.p->prior->next=p->next;
2.p->next->prior=p->prior;
3.free(p).
### 十三、总结
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-15_56c1368d80688.jpg)
';