1.概念
线性表可以看做一种抽象的概念,也可以作为一种抽象数据类型,一个线性表是某类元素的集合,还记录着元素之间的一种顺序关系。相当于一个抽象类,只做定义。
2.具体实现
1.顺序表
顺序表的基本实现方式非常简单:表中元素顺序存放在一片足够大的连续储存区间里,首元素存入储存区的开始位置,其余元素依次顺序存放,元素之间的逻辑关系通过元素在储存区里的物理位置表示(隐式表示元素之间的关系)
顺序表在内存中的布局方式:
1.顺序表基本操作的实现
-
创建和访问操作
创建空表时,需要分配一块元素储存,记录表的容量,并将元素计数设置为0,复杂度为O(1)
-
简单判断操作
判断表空或表满的操作很容易实现,复杂度都为O(1)
-
访问给定下标i的元素
不依赖表中元素个数,因此也是O(1)操作
-
遍历操作
要顺序访问表中元素,在遍历过程中记录遍历到达位置,再算出元素位置,即可获取到元素。获取每一个元素的复杂度为O(1),所以遍历整个表的复杂度为O(n)。
-
查找给定元素d的位置
这种操作称为检索或查找,采用遍历的操作,顺序比较,时间复杂度O(n)。
-
查找给定元素d在位置k之后第一次出现的位置
同5相同,只不过从位置k以后遍历。
-
加入元素
在表的尾端加入和删除都很简单,时间复杂度为O(1)。在其他位置添加和删除就要麻烦些,需要移动操作位置后面的数据,向前移动或向后移动,时间复杂度为O(len-i),i为操作位置。
-
删除元素
尾端删除元素操作简单,时间复杂度为O(1),一般位置删除O(n),基于条件的删除O(n)。
总结:
优点:O(1)时间的按位置访问,元素在表里储存紧凑,除表元素外,只需要O(1)空间存放少量的辅助信息。
缺点:需要连续的储存区存放表中元素,如果表很大,就需要大片的连续内存空间,一旦确定了储存块的大小,不会随着数据的插入和删除操作进行变动,会有大量空闲单元存在,造成浪费。
2.顺序表的结构
两种基本实现方式
- 一体式结构
- 分离式结构
-
一体式分析
实现比较紧凑,有关信息集中在一起,整体性强,易于管理。
创建后储存区大小固定
-
分离式分析
表中只保存于整个表有关的信息,实际元素放在另一个独立的元素储存区对象里,通过链接于基本表对相关连,这样的表对象大小统一,但一个表需要两个独立的对象实现,创建和管理工作复杂。分离式实现的最大优点是带来了一种新的可能,可以在标识不变的情况下,为其对象换一块元素储存区,也就是说可以改变表的容量。
-
-
- 另外申请一块更大的存储区
- 把表中已有元素复制到新存储区
- 用新的元素存储区替换原来的元素存储区
- 实际加入新元素
-
在扩容的时候如果每次只扩大10个元素储存位置,那么在大量数据插入的时候,需要不停的更换存储位置,元素频繁复制迁移。如果每次扩大当前储存量的一倍,当数据较大的时候,会造成大量的存储空间浪费。所以扩容的时候采用的策略也需要权衡利弊。
3.python的list
基本实现
- 基于下标高效访问和更新
- 允许任意加入元素,而且在加入过程中表的id不变
解决方案
- 由于需要O(1)时间的元素访问,并能维持元素的顺序,这种表只能采用连续表技术
- 要求容纳任意多的元素,就必须能更换元素存储区,所以只能采用分离式技术实现。
实际策略
- 在建立空表或很小的表时,系统分配一块能容纳8个元素的存储区,如果满了就换一块4倍大的存储区
- 如果表的容量达到50000时,换储存区时容量加倍
4.顺序表的简单总结
- 最重要的特点是O(1)时间的定位元素访问,更新。很多简单操作的效率也比较高。
- 最麻烦的是加入,删除等操作的效率问题
- 需要连续的存储空间
- 结构不够灵活
2.链接表
-
单链表
在这样的结构中,为了掌握一个表,只需要用一个变量保存着这个表的首节点的引用
-
- 一个单链表由一些具体的表节点构成
- 每个节点是一个对象,有自己的标识,也称为该节点的链接
- 节点之间通过链接建立起单向的顺序联系
- 链表的结束只需在最后的节点的链接域设置一个None。
2.1.1. 基本操作
-
- 创建空链表:只需要把相应的表头变量设置为空链接。
- 删除链表:丢弃这个链表里的所有节点,python里只需要将表指正赋值为None,python解释器会自动回收不用的存储。
- 判断是否为空:将表头变量的值与空链接值比较
- 判断是否满:一般而言链表不会满,除非程序用完了所有的存储空间
- 首端插入:
-
- 创建一个新节点并存入数据
- 把原链表首节点的链接存入新节点的链接域next
- 修改表头变量,使之指向新节点
- 一般情况下的插入
-
- 找到插入位置
- 执行首端操作的三步
- 删除表首元素:只需修改表头指针,令其指向第二个节点
- 一般情况下的删除:找到元素前一节点所在位置,next域改为元素后一节点的链接
- 扫描、定位和遍历:由于单链表只有一个方向的链接,开始时只有表头的链接在掌握中,所以对表内内容的一切检查都只能从表头开始,沿表中链接逐步进行,过程称为扫描。
-
- 按下标定位
- 按元素定位
-
- 操作复杂度
- 创建空表:O(1)
- 删除表:在python里是O(1)
- 判断空:O(1)
- 加入元素或删除:
- 首端加入:O(1)
- 尾端加入:O(n)
- 随意加入:O(n),平均和最坏情况都是
- 求表的长度:需要扫描整个,得出长度,也可以把长度记录为表的数据成分,O(1)
- 操作复杂度