线性表(顺序表,单链表,双链表,循环链表,静态链表)

目录

  • 1.线性表的定义
    • 1.几个重要的概念
    • 2.逻辑结构
  • 2.线性表的基本操作
  • 3.顺序表(线性表的顺序存储)
    • 1.静态分配
    • 2.动态分配
    • 3.顺序表的特点
    • 4.顺序表的基本操作
      • 1.插入
      • 2.删除
      • 3.查找
        • 1.按位查找
        • 2.按值查找
  • 4.链表(线性表的链式存储)
    • 1.单链表
      • 1.代码实现
      • 2.带头结点的实现
      • 3.不带头结点的实现
      • 4.按位序插入
      • 5.指定结点的后插操作
      • 6.指定结点的前插操作
      • 7.按位序删除
      • 8.指定结点的删除
      • 9.按位查找
      • 10.按值查找
      • 11.求表的长度
    • 2.单链表的建立
      • 1.尾插法
      • 2.头插法
    • 3.双链表
      • 1.初始化
      • 2.插入
      • 3.删除
      • 4.遍历
    • 4.循环链表
      • 1.循环单链表
        • 1.初始化
        • 2.基本操作
      • 2.循环双链表
        • 1.初始化
        • 2.基本操作
    • 5.静态链表
      • 1.定义
      • 2.代码实现
      • 3.基本操作
  • 5.顺序表和链表的对比
    • 1.逻辑结构
    • 2.存储结构
    • 3.基本操作
      • 1.创建
      • 2.销毁
      • 3.增删
      • 4.查找
    • 4.选择

1.线性表的定义

线性表是具有相同数据类型的n (n>=0)个数据元素的有限序列,其中n为表长,当n = 0时线性表是一个空表。
若用L命名线性表,则其一般表示为 L = ( a 1 , a 2 , . . . , a i , a i + 1 , . . . , a n ) L= (a1, a2,... , a_i, a_{i+1}, ... , an) L=(a1,a2,...,ai,ai+1,...,an)

1.几个重要的概念

a i a_i ai是线性表中的“第i个”元素线性表中的位序
注意:位序从1开始,数组下标从0开始。
a 1 a_1 a1表头元素;
a n a_n an表尾元素
除第一个元素外,每个元素有且仅有一个直接前驱;
除最后一个元素外,每个元素有且仅有一个直接后继.

2.逻辑结构

在这里插入图片描述

2.线性表的基本操作

“&”符号的作用:对参数的修改结果带回主函数

①InitList(&L):初始化表。构造一个空的线性表L,分配内存空间
②DestroyList(&L):销毁操作。销毁线性表,并释放线性表L所占用的内存空间。
③ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e.
④ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值。
⑤LocateElem(L,e):按值查找操作。在表L中查找具有给定关键字值的元素。
⑥GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值。
⑦Length(L):求表长。返回线性表L的长度,即L中数据元素的个数。
⑧PrintList(L):输出操作。按前后顺序输出线性表L的所有元素值。
⑨Empty(L):判空操作。若L为空表,则返回true,否则返回false。

3.顺序表(线性表的顺序存储)

顺序表:用顺序存储的方式实现线性表。
顺序存储:把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现。
顺序表的实现方式:静态分配和动态分配。

1.静态分配

存储空间是静态的。
使用“静态数组”实现,大小一旦确定就无法改变。

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第1张图片

2.动态分配

C语言中提供malloc和free函数来动态申请和释放内存空间。
使用动态数组实现。
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第2张图片

3.顺序表的特点

随机访问,即可以在(O1)时间内找到第i个元素。
②存储密度高,每个节点只存储数据元素。
③拓展容量不方便(即便采用动态分配的方式实现,拓展长度的时间复杂度也比较高)
④插入、删除操作不方便,需要移动大量元素。

4.顺序表的基本操作

1.插入

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第3张图片

①最好情况:新元素插入到表尾,不需要移动元素。
i = n + 1 i = n+1 i=n+1,循环0次;最好时间复杂度=O(1)
②最坏情况:新元素插入到表头,需要将原有的n个元素全都向后移动。
i = 1 i = 1 i=1,循环n次;最坏时间复杂度= O(n);
③平均情况:假设新元素插入到任何一个位置的概率相同,
i = 1 , 2 , 3 , . . , l e n g t h + 1 的概率都是 p = 1 n + 1 i=1,2,3,.. , length+1的概率都是p=\frac{1}{n+1} i=1,2,3,..,length+1的概率都是p=n+11
平均循环次数= n ( n + 1 ) 2 1 n + 1 = n 2 \frac{n(n+1)}{2}\frac{1}{n+1}=\frac{n}{2} 2n(n+1)n+11=2n平均时间复杂度= O(n)

2.删除

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第4张图片

①最好情况:删除表尾元素,不需要移动其他元素。
i = n,循环0次;最好时间复杂度=O(1)
②最坏情况:删除表头元素,需要将后续的n-1个元素全都向前移动。
i = 1,循环n-1 次;最坏时间复杂度= O(n);
③平均情况:假设删除任何一个元素的概率相同,即 i = 1 , 2 , 3 , . . . , l e n g t h i= 1,2,3,... , length i=1,2,3,...,length的概率都是 p = 1 n p =\frac{1}{n} p=n1
平均循环次数 = n ( n − 1 ) 2 1 n = n − 1 2 \frac{n(n-1)}{2}\frac{1}{n}=\frac{n-1}{2} 2n(n1)n1=2n1平均时间复杂度= O(n)

3.查找

1.按位查找

GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值。
由于顺序表的各个数据元素在内存中连续存放,因此可以根据起始地址和数据元素大小立即找到第i个元素:“随机存取”特性。
时间复杂度为O(1)

2.按值查找

LocateElem(L,e):按值查找操作。在表L中查找具有给定关键字值的元素。
最好情况:目标元素在表头,循环1次;最好时间复杂度=O(1)
最坏情况:目标元素在表尾,循环n 次;最坏时间复杂度= O(n);
平均情况:假设目标元素出现在任何一个位置的概率相同,都是 1 n \frac{1}{n} n1,平均循环次数= n ( n + 1 ) 2 1 n = n + 1 2 \frac{n(n+1)}{2}\frac{1}{n}=\frac{n+1}{2} 2n(n+1)n1=2n+1
平均时间复杂度= O(n)

4.链表(线性表的链式存储)

1.单链表

单链表由一个一个结点组成,每个结点除了存放数据元素外,还要存储指向下一个节点的指针。
优点:不要求大片连续空间,改变容量方便。
缺点:不可随机存取,要耗费一定空间存放指针。

1.代码实现

强调这是一个单链表:使用 L i n k L i s t LinkList LinkList
强调这是一个结点:使用 L N o d e ∗ LNode * LNode
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第5张图片

2.带头结点的实现

头指针本身不存储数据,数据域为空,只有他指向的下一个结点开始存储数据。
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第6张图片

3.不带头结点的实现

不带头结点,写代码更麻烦。
对第一个数据结点和后续数据结点的处理需要用不同的代码逻辑,对空表和非空表的处理需要用不同的代码逻辑。

4.按位序插入

Listlnsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。
①带头结点
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第7张图片
平均时间复杂度:O(n)
②不带头结点
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第8张图片

5.指定结点的后插操作

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第9张图片

6.指定结点的前插操作

①使用带头指针的链表,循环查找元素的前驱,再对元素前驱进行后插操作。
时间复杂度为O(n)
②将新增结点复制为需要进行前插操作的结点,再将待插入的数据的数据域复制给当前结点,连接两个结点即可。
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第10张图片
时间复杂度为O(1)

7.按位序删除

ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值。
找到第i-1个结点,将其指针指向第i+1个结点,并释放第i个结点。

①带头结点
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第11张图片
最环、平均时间复杂度:O(n)
最好时间复杂度:O(1)

8.指定结点的删除

删除结点p,需要修改其前驱结点的next指针,
方法1:传入头指针,循环寻找p的前驱结点
方法2:偷天换日(类似于结点前插的实现)
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第12张图片
时间复杂度为O(1),但如果p为最后一个结点时会存在空指针问题

9.按位查找

平均时间复杂度为O(n).

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第13张图片

10.按值查找

平均时间复杂度为:O(n)
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第14张图片

11.求表的长度

平均时间复杂度为:O(n)
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第15张图片

2.单链表的建立

1.尾插法

时间复杂度:O(n)
要设置一个指向表尾结点的指针。

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第16张图片

2.头插法

应用:链表的逆置
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第17张图片

3.双链表

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第18张图片

1.初始化

增加了一个指向前驱的指针域。
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第19张图片
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第20张图片
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第21张图片

2.插入

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第22张图片

3.删除

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第23张图片

4.遍历

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第24张图片

双链表不可随机存取,按位查找,按值查找操作都只能用遍历的方式实现。
时间复杂度O(n)

4.循环链表

1.循环单链表

表尾结点的next指针指向头结点。
从一个结点出发可以找到其他任何一个结点。

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第25张图片

1.初始化

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第26张图片

2.基本操作

①从头结点找到尾部,时间复杂度为O(n)
②从尾部找到头部,时间复杂度为O(1)
③很多时候对链表的操作都是在头部或尾部,可以让L指向表尾元素(插入、删除时可能需要修改L)。

2.循环双链表

表头结点的prior指向表尾结点。
表尾结点的next指向头结点。
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第27张图片

1.初始化

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第28张图片

2.基本操作

①插入
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第29张图片
②删除
线性表(顺序表,单链表,双链表,循环链表,静态链表)_第30张图片

5.静态链表

1.定义

静态链表:分配一整片连续的内存空间,各个结点集中安置。
静态链表:用数组的方式实现的链表。

优点:增、删操作不需要大量移动元素
缺点:不能随机存取,只能从头结点开始依次往后查找。
容量固定不可变
适用场景:
①不支持指针的低级语言;
②数据元素数量固定不变的场景(如操作系统的文件分配表FAT)

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第31张图片

2.代码实现

线性表(顺序表,单链表,双链表,循环链表,静态链表)_第32张图片

3.基本操作

①查找
从头结点出发挨个往后遍历结点。时间复杂度为O(n)

②插入
找到一个空的结点,存入数据元素
从头结点出发找到位序为i-1的结点
修改新结点的next
修改i-1号结点的next

③删除
从头结点出发找到前驱结点
修改前驱结点的游标
被删除结点next设为-2

5.顺序表和链表的对比

1.逻辑结构

都属于线性表,都是线性结构

2.存储结构

①顺序表(顺序存储)
优点:支持随机存取、存储密度高。
缺点:大片连续空间分配不方便,改变容量不方便。

②链表(链式存储)
优点:离散的小空间分配方便,改变容量方便。
缺点:不可随机存取,存储密度低。

3.基本操作

1.创建

①顺序表
需要预分配大片连续空间。
若分配空间过小,则之后不方便拓展容量;
若分配空间过大,则浪费内存资源。
②链表
只需分配一个头结点(也可以不要头结点,只声明一个头指针),之后方便拓展。

2.销毁

①顺序表
修改Length=0
系统自动回收空间

②链表
依次删除各个结点( free )
需要手动free

3.增删

①顺序表
插入/删除元素要将后续元素都后移/前移
时间复杂度O(n)
时间开销主要来自移动元素
若数据元素很大,则移动的时间代价很高

②链表
插入/删除元素只需修改指针即可
时间复杂度o(n)
时间开销主要来自查找目标元素
查找元素的时间代价更低

4.查找

①顺序表
按位查找:O(1)
按值查找:O(n)若表内元素有序,可在 O ( l o g 2 n ) O(log_2n) O(log2n)时间内找到

②链表
按位查找:O(n)
按值查找:O(n)

4.选择

表长难以预估、经常要增加/删除元素—―链表。
表长可预估、查询(搜索)操作较多――顺序表。

你可能感兴趣的:(数据结构与算法,链表,网络,数据结构,算法)