当前位置: 首页 > news >正文

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

目录

  • 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.静态分配

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

在这里插入图片描述

2.动态分配

C语言中提供malloc和free函数来动态申请和释放内存空间。
使用动态数组实现。
在这里插入图片描述

3.顺序表的特点

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

4.顺序表的基本操作

1.插入

在这里插入图片描述

①最好情况:新元素插入到表尾,不需要移动元素。
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.删除

在这里插入图片描述

①最好情况:删除表尾元素,不需要移动其他元素。
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
在这里插入图片描述

2.带头结点的实现

头指针本身不存储数据,数据域为空,只有他指向的下一个结点开始存储数据。
在这里插入图片描述

3.不带头结点的实现

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

4.按位序插入

Listlnsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。
①带头结点
在这里插入图片描述
平均时间复杂度:O(n)
②不带头结点
在这里插入图片描述

5.指定结点的后插操作

在这里插入图片描述

6.指定结点的前插操作

①使用带头指针的链表,循环查找元素的前驱,再对元素前驱进行后插操作。
时间复杂度为O(n)
②将新增结点复制为需要进行前插操作的结点,再将待插入的数据的数据域复制给当前结点,连接两个结点即可。
在这里插入图片描述
时间复杂度为O(1)

7.按位序删除

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

①带头结点
在这里插入图片描述
最环、平均时间复杂度:O(n)
最好时间复杂度:O(1)

8.指定结点的删除

删除结点p,需要修改其前驱结点的next指针,
方法1:传入头指针,循环寻找p的前驱结点
方法2:偷天换日(类似于结点前插的实现)
在这里插入图片描述
时间复杂度为O(1),但如果p为最后一个结点时会存在空指针问题

9.按位查找

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

在这里插入图片描述

10.按值查找

平均时间复杂度为:O(n)
在这里插入图片描述

11.求表的长度

平均时间复杂度为:O(n)
在这里插入图片描述

2.单链表的建立

1.尾插法

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

在这里插入图片描述

2.头插法

应用:链表的逆置
在这里插入图片描述

3.双链表

在这里插入图片描述

1.初始化

增加了一个指向前驱的指针域。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.插入

在这里插入图片描述

3.删除

在这里插入图片描述

4.遍历

在这里插入图片描述

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

4.循环链表

1.循环单链表

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

在这里插入图片描述

1.初始化

在这里插入图片描述

2.基本操作

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

2.循环双链表

表头结点的prior指向表尾结点。
表尾结点的next指向头结点。
在这里插入图片描述

1.初始化

在这里插入图片描述

2.基本操作

①插入
在这里插入图片描述
②删除
在这里插入图片描述

5.静态链表

1.定义

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

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

在这里插入图片描述

2.代码实现

在这里插入图片描述

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.选择

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

相关文章:

  • Linux中命令lsattr/chattr
  • react_6
  • 全面的Docker快速入门教程
  • U盘显示无媒体怎么办?方法很简单
  • 在校园跑腿系统小程序中,如何设计高效的实时通知与消息推送系统?
  • ARCGIS---dem生成高程点
  • 最近又考了两个Oracle认证,交一下作业
  • LV.12 D17 中断控制器 学习笔记
  • 前端的几种网络请求方式
  • 内涝积水监测仪怎么样?万宾科技城市内涝积水监测的作用
  • ZZ038 物联网应用与服务赛题第J套
  • 为什么是LangChain?
  • easyHttp -- 轻量级的 HTTP 客户端工具包
  • 有限域的Fast Multiplication和Modular Reduction算法实现
  • mermaid学习第一天/更改主题颜色和边框颜色/《需求解释流程图》
  • (三)从jvm层面了解线程的启动和停止
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • 0x05 Python数据分析,Anaconda八斩刀
  • Mysql5.6主从复制
  • ng6--错误信息小结(持续更新)
  • NSTimer学习笔记
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • Protobuf3语言指南
  • Spring-boot 启动时碰到的错误
  • windows-nginx-https-本地配置
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 简单易用的leetcode开发测试工具(npm)
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 详解移动APP与web APP的区别
  • 学习笔记TF060:图像语音结合,看图说话
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • ​configparser --- 配置文件解析器​
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • ​Python 3 新特性:类型注解
  • ​低代码平台的核心价值与优势
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • $GOPATH/go.mod exists but should not goland
  • (C语言)字符分类函数
  • (二)windows配置JDK环境
  • (九)c52学习之旅-定时器
  • (算法设计与分析)第一章算法概述-习题
  • (循环依赖问题)学习spring的第九天
  • .【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)
  • .net 程序发生了一个不可捕获的异常
  • .netcore如何运行环境安装到Linux服务器
  • .net安装_还在用第三方安装.NET?Win10自带.NET3.5安装
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • .sh 的运行
  • .sys文件乱码_python vscode输出乱码
  • [AutoSar NVM] 存储架构