第三章:线性表。
List:零个或多个数据元素的有限序列。
线性表存储结构
顺序存储结构:
用一段连续地址的存储单元依次存储线性表的数据元素。
三个属性:
*emsp;存储空间的起始位置。
最大存储容量。
线性表的当前长度。
地址计算:
起始下表为0,第i个数据元素地址为(i-1)*固定数据空间长度 + 起始地址
无论位置在哪都是一次计算,对于计算机而言都是相等的存取时间,时间复杂度0(1)。随机存储结构。
查询 GetElem:
查询的下标必须在数组下标范围内。
插入 ListInsert:
如果插入位置不合理,抛出异常;
如果线性表长度大于数组长度,则抛出异常或动态增加容量;
从最后一个元素开始向前遍历到第i个位置,分别将它们都后移一位。
将要插入的元素填入位置i处;
表长加1.
删除 DelElem:
如果删除位置不合理,抛出异常;
取出删除元素;
从删除位置到最后一个位置,进行遍历,全部向前移动一位;
表长减1.
线性表顺序存储结构的优缺点:
优点:
无须为表示表中元素之间的逻辑关系而增加额外的存储空间;
可以快速存取表中任一位置的元素;
缺点:
插入和删除操作需要移动大量元素;
当线性表长度变化较大时,难以确定存储结构的容量;
造成存储空间的碎片。
链式存储结构:
链式结构,除了存储数据元素外,还要存储它的后继元素的地址。
数据域和指针域。
单链表:每个结点只有一个指针域。存在头指针和最后一个结点指针为NULL。
单链表的第一个结点前附设一个结点,称为头结点。存储线性表的长度等附加信息。
单链表的读取
思路:
1 声明一个p指向链表的第一个结点,初始化j从1开始;
2 当j<i时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1;
3 若到链表末尾p为空,则说明第i个元素不存在;
4 否则查找成功,返回结点p的数据。
时间复杂度:O(n)
单链表没有定义表长,事先不知道要循环多少次,因此也就不方便使用for来控制循环。
单链表的插入
算法思路:
1 声明一结点p指向链表第一个结点,初始化j从1开始;
2 j< i 时,就遍历链表,p的指针后移,不断指向下个结点,j累加1;
3 若链表末尾p为空,则说明第i个元素不存在;
4 否则查找成功,内存中新建一个空结点s;
5 将数据元素e赋值给s -> data;
6 单链表的插入标准语句:s->next = p->next; p->next=s;
7 返回成功
单链表的删除
算法思路:
1 声明一个p指向链表的第一个结点,初始化j从1开始;
2 当j<i时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1;
3 若到链表末尾p为空,则说明第i个元素不存在;
4 否则查找成功,将欲删除的结点p->next 赋值给q;
5 单链表的删除标准语句p->next=q->next;
6 将q结点中的数据赋值给e,作为返回;
7 释放q结点;
8 返回成功
单链表的创建
算法思路:
1 声明一个p和计数器变量i;
2 初始化一空链表L;
3 让L的头结点的指针指向NULL,即建立一个带头结点的单链表;
4 循环:
- 生成一新结点赋值给p;
- 随机生成一数字赋值给p的数据域 p->data;
- 将p插入头结点与前一新结点之间。
静态链表
数组的元素都是两个数据域,data和cur。数组描述的链表叫做静态链表。
- 静态链表的插入操作
实现不移动元素,插入了数据。
- 静态链表的删除操作
把要删除的元素改为空闲元素,更改链表第一个元素和最后一个元素的cur数据域。
循环链表
将单链表中终端结点的指针端由空指针改为指向头结点,使得整个链表形成一个环,这种链表称之为单循环链表。
具有头结点:可以通过判断p->next是否指向头结点,得到循环是否结束。具有头指针。
具有尾指针:查找终端结点和头结点都是0(1),两个链表的合并也是很简单。
双向链表
double linked list 是在单链表的每一个结点中设置一个指向其前驱结点的指针域。
双向链表支持反向遍历查找。但在插入和删除时需要操作两个指针变量。