第二章线性表

2.1 线性表的定义和基本操作

线性表的定义

​ 线性表是具有相同数据类型的 n(n≥0)个数据元素的有限序列,其中 n 为表长,当 n = 0 时线性表是一个空表。若用 L 命名线性表,则其一般表示为 L = (a 1, a 2, … , ai , ai+1, … , an)

​ ai 是线性表中的 “第 i 个” 元素线性表中的位序

​ a 1 是表头元素;an 是表尾元素

​ 除第一个元素外,每个元素有且仅有一个直接前驱;除最后一个元素外,每个元素有且仅有一个直接后继

线性表的基本操作

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 个位置的元素的值。

& 表示 C++ 中的引用, 若传入指针型变量且在函数体内要进行改变, 要用到指针变量的引用 (C 中用指针的指针也可以)

2.2 线性表的顺序表示

顺序表的定义

顺序表——用顺序存储的方式实现线性表

顺序存储:把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现

顺序表的实现 :静态分配、动态分配

动态分布语句:

 L.data=(ElemType*)malloc(sizeof(ElemType)*InitSize)
//malloc函数申请一片连续的存储空间
//free函数释放原来的内存空间

动态分配不是链式存储, 同样属于顺序存储结构, 物理结构没有变化: 随机存取方式, 只是分配的空间大小可以在运行时决定

特点: 随机访问, 存储密度高, 插入和删除需要移动大量元素

顺序表的操作

1. **插入操作**  平均时间复杂度O(n)
2. **删除操作**  平均时间复杂度O(n)

  1. 查找操作:按值查找、按位查找

2.3 线性表的链式表示

单链表

头指针和头结点的区别:(1)不管带不带头结点, 头指针始终指向链表的第一个结点

​ (2)头结点是带头结点的链表中的第一个结点, 通常不存储信息

引入头结点的优点:无论链表是否为空, 头指针都指向头结点的非空指针, 空表和非空表处理一致

单链表的操作

建立单链表

核心:初始化操作、指定结点的后插操作

​ (1)头插法,链表的逆置

​ (2)尾插法,注意设置一个指向表尾结点的指针

插入结点操作

​ (1)按位序插入(带头结点)

​ (2)按为序插入(不带头结点)

​ (3)指定结点的前插操作: 先找到前一个结点, 时间复杂度为 O (n)

​ (4) 将前插操作转化为后插操作, 然后交换两个结点的数据, 时间复杂度为 O (1)

删除结点操作

​ (1)按位序删除(带头结点)

​ (2)指定结点的删除:先找到前驱节点, 再删除结点, O (n)

查找结点操作

​ (1)按位查找

​ (2)按值查找

双链表

循环链表

​ (1)循环单链表:表尾结点的 next 指针指向头结点

​ 对单链表在表头和表尾操作时: 不设头指针仅设尾指针, 效率更高

​ 可以从任意一个结点开始遍历整个链表

​ (2)循环双链表:表头结点的 prior 指向表尾结点,表尾结点的 next 指向头结点

静态链表

用数组描述链式存储结构, 也有数据域和指针域. 指针是结点的相对地址 (数组下标), 又称游标

插入和删除只需要修改指针, 不需要移动元素

顺序表和链表的比较

  1. 逻辑结构都属于线性表,都是线性结构

  2. 存储结构顺序表:顺序存储链表:链式存储

  3. 基本操作–初始化

  4. 基本操作–增删

  5. 基本操作–查

  6. 如何选择

    (1)基于存储的考虑 :难以估计长度和存储规模时用链表, 但链表的存储密度较低

    (2)基于运算的考虑:经常做按序号访问数据元素用顺序表

    (3)基于环境的考虑:较稳定选顺序表, 动态性较强选链表