顺序表(顺序存储)

定义:

image.png
image.png

线性表的存储结构 - 图3

基本操作的实现:

内存分配:

静态分配(数组):

image.png

动态分配[malloc-free(头文件stdlib.h)/new-delete(面向对象)]:

image.png示例代码:
image.png

顺序表的特点:

image.png

总结:

image.png

7.gif

插入与删除:

插入:

分析:
image.png
实现:
image.png
时间复杂度分析:
image.png

删除:

实现:
image.png
时间复杂度分析:
image.png

总结:

image.png
线性表的存储结构 - 图16

查找:

按位查找:

静态分配的查找:
image.png
动态分配的查找:
image.png
时间复杂度分析:
image.png

按值查找:

image.png
时间复杂度:
image.png

总结:

image.png

链式表(链式结构)

单链表

什么是单链表:

image.png

不带头节点的单链表:

image.png

带头结点的单链表:

image.png

不带头节点VS带头节点:

image.png

总结1:

image.png

单链表的插入和删除:

线性表的存储结构 - 图28
头节点插入:
image.png
不带头节点(对插入第一个结点做特殊处理):
image.png
指定结点的后插操作(给定结点p):
image.png
通过调用函数可简化前面的代码
指定结点的前插操作:(给定结点p,寻找其前驱结点
①首先要遍历列表,找到要插入位置的前一个结点在哪,然后就可以进行插入操作。时间复杂度为O(N)
image.png
②这里介绍一种插入方法,要插入结点的数据复制一个新的结点,此节点的数据改为要插入的数据,然后将复制数据插入列表。这样不需要知道前驱节点。且时间复杂度位O(1)(此方法不需要查找p的前驱结点)
image.png
删除指定位序的结点:
image.png
指定结点删除,复制后面的结点数据给要删除的结点,然后删除后面结点,时间复杂度为O(1)
image.png
如果是最后一个结点的删除,上述代码会报错,只能遍历列表寻找前驱:
image.png

单链表的建立:

线性表的存储结构 - 图37
image.png
步骤(具体代码请看前面笔记,这里只介绍一些新的知识):
①建立一个链表,一般建立带头节点的链表

②执行前插或者后插操作
A.尾插:
image.png
双尾指针法:
image.png
s虽然在过程中指向了其他空间,但是最后r,s始终指向末尾数据。输入9999时会将末尾设置为null,结束后返回L指针
B.头插
image.png
image.png

思考:不带头节点的头插法
去掉会出现野指针(指向未知区域)的情况,最终导致数据异常,因此要习惯于初始化链表时将头节点指向null
头插法的重要运用:链表的逆置
①创建一个新的链表逆置,使用头插法(旧链表的第一个元素变为了新链表的最后一个元素),逆指旧的链表,最终让头指针指向新的链表。
②原地逆置,将链表的后面数据前插到链表前面
注:使用指针来扫描链表获取数据

总结2:

image.png

双链表

带头结点的双链表的的初始化:

image.png

双链表的插入:

注意判断插入位置是否为有后继节点
image.png

双链表的删除:

注意删除的结点有没有后继节点
image.png

双链表的遍历操作:

双链表不支持随机存取(什么是随机存取见知识补充),按位查找(找到指定位置上的结点)、按值查找(找到指定的值)都需要遍历链表,其时间复杂度为O(N)
image.png

总结:

image.png

循环列表:

在链表的基础上是最后一个结点的指针不指向null,而指向头节点

循环单链表:

image.png
初始化:将头节点的next指针指向自己,判断循环单链表是否为空时判断头结点的指针是否与L指向的地址相同(都指向头节点)。
image.png
判断一个结点是否是尾部结点时判断指针是否指向头节点
image.png

循环双链表:

image.png
初始化循环双链表及判断链表是否为空和尾结点:
image.png
循环双链表的插入:
非循环链表在尾结点后插时由于尾结点会出现一定的问题,而循环链表则没有该类问题
image.png
循环双链表的删除:
非循环链表在删除尾结点时由于尾结点会出现一定的问题,而循环链表则没有该类问题
image.png

总结:

image.png

静态链表:

image.png