大话数据结构笔记-线性表
基础知识
线性表(List):零个或多个数据元素的有限序列。
重点:有顺序、有限
例如有一个线性表:a, b, c, d, ···, z
则:
- a是b的直接前驱元素
- b是a的直接后继元素
- 每个元素至多有一个直接前驱元素和直接后继元素
所有线性表元素的个数n(n>=0)为线性表的长度,n=0时,为空表。
在复杂的线性表中,一个数据元素可以是若干个数据项组成,例如花名册。
顺序存储结构
线性表的数据存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。
顺序存储结构的三个重要 属性:
- 存储空间的起始位置
- 线性表的最大长度
- 线性表的当前长度
地址计算方式
从零开始,第i个元素的的存储位置为i-1。
存储器中每一个存储单元都有自己的编号,这个编号称为 地址。
优缺点
优点:
- 无需为表中的元素之间的逻辑关系而逐渐额外的存储空间
- 可以快速的存取表中任意元素
缺点:
- 插入和删除操作需要移动大量元素
- 当线性表长度变化较大时,难以确定存储空间的容量
- 造成存储空间的“碎片”
链式存储结构
基本定义
- 顾名思义,每个元素像锁链一样环环相连。
- 为了表示每一个元素与其后面元素的关系,在存储自身信息之外还存储其直接后继元素的地址。
- 把存储元素信息的域叫做 数据域,存储后继位置的域叫做 指针域。指针域中存储的信息称为指针或链。
- 两部分组成数据元素的存储映像,称为 结点。
- 链表中的第一个结点的存储位置叫做头指针。
有时,头结点不存储任何信息,有时可以存储线性表的长度等信息。
插入或删除数据越频繁,单链表的优势越大。
头指针和头结点
头指针
- 链表指向第一个结点的指针,若链表有头结点,则指向头结点。
- 具有标识作用,所以常用头指针冠以链表名。
- 无论链表是否为空,头指针均不为空,头指针是链表的必要元素。
头结点
- 头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域一般无意义(或长度)。
- 有了头结点,统一了在第一元素结点前 插入结点和 删除第一结点。
- 头结点不一定是链表必须的元素。
单链表的读、插、删
读:
指针后移,就是说从链表的头结点一个一个找到指定结点。
插:
指针后移找到指定位置的前一个节点(n-1)后,将其指针域指向要插入元素的结点(n),然后将插入元素的指针指向下一元素(n+1).
删:
类似插入,反向操作。
单链表结构与顺序存储结构优缺点
存储分配方式
- 顺序存储结构用一段连续的存储单元依次存储线性表的数据元素。
- 单链表用链式存储结构,用让一组任意的存储单元存放线性表的元素。
时间性能
- 查找:
- 顺序存储:O(1)
- 单链表:O(n)
- 插入删除
- 顺序存储需要平均移动表长度一半的元素O(n)
- 单链表在找出位置后为O(1)
空间性能
- 顺序存储结构需要预先分配存储空间,分大了浪费小了容易发生上溢。
- 单链表不需要分配空间,只要有就可以分配个数也不受限制。
理解
- 当数据很少修改、频繁查询时使用顺序存储反之选择链表
- 当数据大小已知固定不变是可以使用顺序存储
- 其实还是要根据情况判断。
静态链表
对于没有指针的语言,使用数组来实现链表,就形成了静态链表。
也是说,将数组的每个元素分成两个数据域,一个(data)用来存储数据,一个(cur)用来存储下一元素的下标。
静态链表需要数组长度大一些方便插入数据。
我个人理解就是一个二维数组:
array = [
0 => ["数据","下一数据的key"],
...
];
静态链表的插入与删除
用静态模拟动态链表结构,需要时申请、无用时释放。
类似于单链表,只不过是在数组内部完成。
优缺点
优点
- 在插入和删除操作时只需要修改游标,不需要移动元素,从而改进了在顺序存储结构中的插入删除操作需要移动大量元素的缺点。
缺点
- 没有解决连续存储分配带来的表长难以确定的问题。
- 失去了顺序存储结构随机存取的特性。
静态链表是为了给没有指针的高级语言设计的一种实现单链表能力的方法。
循环链表
将单链表的终端节点的指针端由空指针改为指向头结点,使整个单链表形成一个还,这种头尾相接的单链表称为单循环链表,简称单链表。
贪吃蛇
双向链表
在单链表的每个结点中在添加一个指向其前驱结点的指针域。
当然,将双向链表首尾相接就形成了双向循环链表。
总结
- 线性表
- 顺序存储结构
- 链式存储结构
- 单链表
- 静态链表
- 循环链表
- 双向链表