线性表
Posted lygzcom
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性表相关的知识,希望对你有一定的参考价值。
线性表
线性结构的基本特点是除第一个元素无直接前驱,最后一个元素无直接后继之外,其他每个数据元素都有一个前驱和后继。
由n (n>=0)个数据特性相同的元素构成的有限序列称为线性表。
线性表中元素的个数n定义为线性表的长度,n =0 时称为空表。
一、线性表的基本操作
操作 | 初始条件 | 结果 |
---|---|---|
InitList () | 无 | 构造一个空的线性表L |
DestroyList() | 线性表L已存在 | 销毁线性表L |
ClearList () | 线性表L已存在 | 将L重置为空表 |
ListEmpty() | 线性表L已存在 | 若L为空表, 则返回true, 否则返回false |
ListLength() | 线性表L已存在 | 返回L中数据元素个数 |
GetElem(L,i) | 线性表L已经存在,且1<=i<=ListLength | 返回L中第i个数据元素的值 |
LocateElem(L,e) | 线性表L已存在 | 返回L中第1个值与e相同的元素在 L中的位置 。若这样的数据元素不存在 , 则返回值为-1 |
PriorElem(L,cur_e,pre_e) | 线性表L已存在 | 若cur_e是L的数据元素,且不是第一个,则用pre_e返回其前驱 |
NextElem(L,cur_e,next_e) | 线性表L已存在 | 若cur_e是L的数据元素,且不是最后一个,则用next_e返回其后继 |
Listinsert(L,i,e) | 线性表L已存在,且1<=i<=ListLength | 在 L中第i个位置之前插入新的数据元素 e, L的长度加1 |
ListDelete(L,i) | 线性表L已存在且非空 ,且1<=i<=ListLength | 删除L的第i个数据元素,L的长度减1 |
TraverseList() | 线性表L已存在 | 对线性表L进行遍历,在遍历过程中对 L的每个结点访问一次 |
二、线性表的顺序存储结构
2.1顺序存储结构特点
-
连续内存
-
随机访问O(1)
-
查找平均时间复杂度O(n)
-
插入删除平均时间复杂度O(n)
总结:
顺序表可以随机存取表中任一元素,其存储位置可用一个简单、直观的公式来表示。然而,从另一方面来看,这个特点也造成了这种存储结构的缺点:在做插入或删除操作时,需移动大最元素。另外由于数组有长度相对固定的静态特性当表中数据元素个数较多且变化较大时,操作过程相对复杂,必然导致存储空间的浪费。
三、表的链式存储结构
3.1 线性表链式存储结构的特点
- 用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。
- 线性表链式存储结构的每一个元素称为结点。
- 节点分为两个域:其中存储数据元素信息的域称为数据域;存储直接后继存储位置的域称为指针域。指针域中存储的信息称作指针或链。
- 头结点:第一个节点,通常不带数据域。
- 头指针:链表的头部,具有头结点指向头结点,没有头结点指向首元结点。
- 首元结点:第一个数据域节点。
头结点的意义
- 便于首元结点的处理:
增加了头结点后,首元结点的地址保存在头结点即其("前驱"结点)的指针域中,则对链表的第一个数据元素的操作与其他数据元素相同,无需进行特殊处理。- 便于空表和非空表的统一处理:
链表不设头结点时,假设 L 为单链表的头指针,它应该指向首元结点,则当单链表为长度n 为 0 的空表时, L 指针为空(判定空表的条件可记为:L== NULL);增加头结点后,无论链表是否为空,头指针都是指向头结点的非空指针。非空单链表,头指针指向头结点。若为空表,则头结点的指针域为空(判定空表的条件可记为:L ->next== NULL)。
3.2 链表分类
- 单链表(链表的每个结点中只包含一个指针域,则此链表称为线性链表或单链表)
- 循环链表(比单链表多了尾结点指向头结点的指针)
- 双向链表(比单链表多了指向前一个结点的指针)
3.3 链式存储结构的特点
- 链表在逻辑上是连续的,不关注内存上是否连续
- 链表是顺序读取,无法进行随机读取。
- 单链表查找平均时间复杂度O(n)
- 单链表的插入删除平均时间复杂度是O(n)
3.4 单链表的创建方式
- 头插法(平均时间复杂度O(n))
- 尾插法(需要一个尾指针,平均时间复杂度O(n))
3.5 循环链表
- 循环链表尾结点的判断:尾结点的指针域指向头结点。
- 从任意节点都可以遍历整个链表。
- 某些情况,记录下尾指针比记下头结点要好。
3.6 双向链表
单链表查找直接后继结点的执行时间为 O(1), 而查找直接前驱的执行时间为O(n)。为克服单链表这种单向性的缺点,可利用双向链表 (Double Linked List)。
双向链表的特点:d->next->prior = d->prior->next = d
四、链表和顺序表的对比
4.1 空间性能比较
- 空间分配角度
- 顺序表需要预先估计占用空间大小,可能造成部分空间浪费,元素扩充有一定的限制。
- 链表不需要提前给出空间大小,只要内存足够就可以存储。
- 在无法估计所需要内存大小时可以考虑使用链表。
- 空间利用角度
- 如果不计顺序表空闲内存,顺序表利用利用率明显高于链表。
- 当数据量比较小的时候从空间利用率来说可以考虑使用顺序表。
4.2 时间性能比较
操作 | 条件 | 数组 | 单链表 | 双向链表 |
---|---|---|---|---|
随机读取 | 索引 | O(1) | O(n) | O(n) |
增加 | 索引后 | O(n) | O(n) | O(n) |
增加 | 首节点后 | O(n) | O(1) | O(1) |
增加 | 非首尾节点后 | O(n) | O(1) | O(1) |
增加 | 尾结点后 | O(1) | O(1) | O(1) |
删除 | 索引后 | O(n) | O(n) | O(n) |
删除 | 首节点 | O(n) | O(1) | O(1) |
删除 | 非首尾节点 | O(n) | O(n) | O(1) |
删除 | 尾结点 | O(1) | O(n) | O(1) |
查找 | 任意节点值 | O(n) | O(n) | O(n) |
总结:
- 如果你需要经常添加或删除结点,链表可能是一个不错的选择。
- 如果你需要经常按索引访问元素,数组可能是比链表更好的选择。
以上是关于线性表的主要内容,如果未能解决你的问题,请参考以下文章