线性表
定义
线性表(linear list)是由零个或多个相同类型的数据元素构成的有限序列。
存储结构
顺序存储
- 最简单的存储方法是顺序存储法,即把线性表的数据元素按照逻辑次序顺序地放在一组地址连续的存储空间中,用顺序存储方法存储的线性表称为顺序表(sequential list)。因为存储的类型相同因此每个元素所占的存储空间也相同。
- 因为顺序表存储的每个元素占用的存储空间相同,因此只要知道第一个元素的存储地址,就可以直接计算出任意元素的存储地址,所以顺序表是一种随机存储结构。
- 优点:不需要为表示元素之间的逻辑关系而增加额外的存储空间;可以方便地随机访问任意位置的元素O(n)。
- 缺点:插入和删除操作需要移动大量的数据元素,因此效率比较低;难以选择合适的存储容量,顺序表要求连续的存储空间,在分配时会选择大小比较符合的空间,因此容易产生内存碎片。
链式存储
- 采用动态存储分配的方式,在程序运行时根据实际需要随时申请内存,在不需要时将内存释放,这种链式方式存储的线性表称为链表(linked list)
- 链表在实现时可以分为动态链表和静态链表,从链接方式上又可以分为单链表、双链表和循环链表等。
单链表
- 链表用一组任意的存储单元存放线性表中的各个元素,这组存储单元可以师连续的,也可以不连续,甚至零散地分布在内存的某些位置。为了正确表示结点间的逻辑关系,在存储元素值的同时,还需要存储该元素的直接后继元素的位置信息(指针pointer)如【data,next】,因为这种结构的每个结点只包含一个链域(next),故将这种链表称为单链表(single linked list),结尾为NULL指针。
- 查找算法
- 按位查找 由于链表采用的是一直顺序存取方式,如果要实现随机存取则只能从链表的表头出发,顺着每个结点的指针域往后依次访问每个结点。
- 按值查找 按值查找是指在单链表中查找给定值的结点,找到后返回元素地址或序号。
循环链表
- 定义:如果将单链表终点的指针域指向头结点,则整个链表构成一个环,这种首尾相接的单链表称为单循环链表。
双向链表
- 存储结构: 【 *prev,data, *next】,优点是可以很方便地得到直接前驱元素,这种链表中有两条相反的链域,因此称为双向链表,简称双链表
静态链表
对于使用c++指针来存储结点,结点空间的分配和回收都是由操作符new和delete动态执行的,因此称之为动态链表(dynamic linked list)。对于某些高级语言如java,没有提供指针数据类型,因此多采用数组来描述单链表,用数组元素的下标来模拟链表的指针,这种数组存储的链表结构,称为静态链表。
顺序表与链表的比较
- 时间性能比较
1. 顺序表是由数组实现的,因此是一种随机存储结构,对于表中任意结点存取操作的时间复杂度为O(1),而查找需要从头指针开始顺着链表扫描,平均负责度为O(n),因此如果线性表的主要操作是查找而很少插入或删除操作,则采用顺序表比较合适。
2. 对于链表,在某个位置上进行插入和删除操作,只需要修改指针即可,无需移动大量元素,操作复杂度为O(1)。若插入和删除主要发生在表头和表尾,则采用循环链表更为方便。
- 空间性能比较
1. 顺序表上的存储空间是静态分配的,因此必须提前确定其存储大小,故顺序表常常用于存储规模比较容易确定的线性表。
2. 静态链表也是静态分表的,所以会有相同的问题。但是如果同时存在多个结点类型相同链表,则这些链表可以共享同一静态链表空间。
3. 动态链表的存储空间是动态分配的,因此只要内存空间还有空闲就不会溢出。因此适用于那种长度变化较大或者长度难以估计的线性表。
STL中相关的模板类
- STL中的向量(Vector)是使用数组实现的,因此具有顺序表的所有特点,可以快速存取任意元素,向量是同一种数据类型的对象集合。
- 列表(list)是STL中线性表的链式存储形式,STL标准库中一般采用双向循环链表实现列表。因此list容器不支持"直接"随机访问(可以通过内部实现“随机”,但是效率不如数组),查找某个元素时往往需要遍历相邻的若干元素。其优点是任何位置都可以高效地插入或删除元素,并且不需要移动其他元素。