1/4 往年真题
2/4 期末测验
-
课后选择题
第一章:ACCAC
第二章:ADBCB DDCAB
第三章:D
第四章:B(228)DCA
第五章:DBDDC CACBB AC
第六章:BBDCB
第七章:BBCBA ACBBB 12
第八章:3 2 D 拉链法
第九章:BBADAA
第十章:A(CB)DB CA
-
其他课后习题
https://wws.lanzoui.com/iGYXQqp8m4f
密码:huve
3/4 复习笔记
1 算法分析
1、算法
2、算法的时间复杂度
3、算法的空间复杂度
4、常见的渐进时间复杂度
O(1) < O(log2 n) < O(n) < O(nlog2 n) < O(n^2) < О(n^3) <0(2^n) < O(n!) < O(n^n)
2 线性表
1、顺序表
优点:可以随机地存取表中任何一个元素。
缺点:① 元素的插入、删除需要移动大量的数据元素。插入操作平均移动 n/2 个结点,删除操作平均移动 (n-1)/2 个结点。
② 顺序表要求连续的存储空间,必须预先分配,故最大长度很难确定。
线性表的顺序存储有两种表示方式:静态数组、动态数组。
1)顺序表的插入运算
时间主要消耗在数据的移动上,在第 i 个位置上插入x,从 ai 到an 都要向后 移动一个位置,共需要移动 n-i+1 个元素。时间复杂度为 O(n)。
2)顺序表的删除运算
时间也主要消耗在数据的移动上,删除第 i 个元素时,从 ai+1 到an 都要向前移动一个位置,共需要移动 n-i 个元素。时间复杂度为 O(n)。
3)顺序表的按值查找
主要运算是比较。比较次数与x在表中的位置有关,也与表长有关。按值查找的平均比较次数为 (n+1)/2,时间复杂度为 O(n)。
2、链表
优点:在插入或删除操作时,只需修改相关指针域即可,无需移动结点。
缺点:① 不可以随机地存取表中任何一个元素。
② 为了反映元素之间的逻辑关系,必须附加指针来表示,导致存储空间利用率降低。
在线性表的长度变化较大、频繁插入和删除、表长预难以确定的情况下,最好采用链表作为存储结构。
1)建立单链表。
2)链表的查找运算。
3)链表的插入运算。
4)链表的删除运算。
3、循环链表,双向链表
3 栈
1、允许插入、删除的一端称为栈顶,另一端称为栈底。先进后出,线性结构。
2、进于顺序存储结构的栈需注意:①进栈时栈是否满;②出栈时栈是否空。
4 队列
一、队列
1、允许插入的一端称为队尾,允许删除的一端称为队头。
先进先出,线性结构。出队列顺序 = 入队列顺序。
2、判断循环队列的“空"和"满"
空:Q->rear == Q->front;
满:(Q->rear)%(Q->maxSize) == Q->front;
3、除了栈和队列,还有一种限定性数据结构是双向队列。
4、若以1234作为双向队列的输入序列,满足以下条件的输出队列有:
① 能由输入受限的双向队列得到,但不能由输出受限的双向队列得到:4132
② 能由输出受限的双向队列得到,但不能由输入受限的双向队列得到:4213
③ 既不能由输入受限的双向队列得到,也不能由输出受限的双向队列得到:4231
二、特殊短阵
1、数组:一般采用顺序存储,是随机存取结构。
① 二维数组按行优先寻址:设数组的基址为 LOC(a00),每个数组元素占据d个地址单元,有LOC(aij) = LOC(a00) + (i*n+j)*d
② 二维数组按列优先寻址:设数组的基址为 LOC(a00),每个数组元素占据d个地址单元,有LOC(aij) = LOC(a00) + (j*n+i)*d
2、对称矩阵:将对称矩阵 A 压缩存储到 SA[n(n+1)/2] 中。
5 二叉树
一、树、二叉树
1、树的定义是递归的,特别适合于表示元素之间的层次关系。
2、二叉树:二叉树是有序的,即使只有一棵子树,也要区分左右。
① 满二叉树:所有分支结点都存在左右子树,且叶子结点都在同一层上。
② 完全二叉树:元素依次处于二叉树从上到下、从左到右的位置。
特点:度为1的结点只有0个或1个。叶结点只能在最下层和次下层。
3、二叉树的存储结构
(1)顺序存储结构:适合于满二叉树、完全二叉树。
(2)链式存储结构:适合于二叉树。
二、树、二叉树的性质
① 二叉树的第 i 层上至多有 2^(i-1) 个结点,i≥1。
② 高度为 h 的二叉树上至多有 2^h-1 个结点,h≥0。
③ 二叉树中,若叶结点数量为n0,度为2的结点数量为n2,则有:n0=n2+1。
④ 包含 n 个结点的二叉树高度最小为 ⌊log₂n⌋+1 或 ⌈log₂(n+1)⌉,最大为n。
⑤ 包含 n 个结点的完全二叉树的高度为 ⌊log₂n⌋+1 或 ⌈log₂(n+1)⌉。
推广②:满二叉树第 h 层的结点个数比第 1~h-1 层结点总数多1个。
推广③:度为 m 的树中,若叶结点数量为N0,度为2的结点数量为N2,度为3的结点数量为N3...,度为m的结点数量为Nm,则有:N0=1+N2+2N3+...+(m-1)Nm。
1、树中的结点数等于所有结点的度数+1。
2、度为 m 的树中第 i 层上至多有 m^(i-1)个结点,i≥1。
3、度为 m 高为 h 的树中至多有 (m^h-1)/(m-1) 个结点,h≥1。
4、度为 m 结点数为 n 的树最小高度为 ⌈logm (n(m-1))+1⌉。
6 二叉树的遍历
1、遍历二叉树是对一个非线性结构进行线性化的操作。
(1)先序遍历:递归算法、非递归算法
(2)中序遍历:递归算法、非递归算法
(3)后序遍历:递归算法、非递归算法
(4)层次遍历
2、二叉树的操作包括:插入、删除、二叉树的复制、左右子树的交换。
3、满足下列条件的二叉树:
(1)若先序序列=后序序列,则或为空树,或为只有根结点的二叉树。
(2)若中序序列=后序序列,则或为空树,或为任一结点至多只有左子树的二叉树。
(3)若先序序列=中序序列,则或为空树,或为任一结点至多只有右子树的二叉树。
(4)若中序序列=层次序列,则或为空树,或为任一结点至多只有右子树的二叉树。
① 若先序序列与后序序列相反,则或为空树,或每层只有一个结点的二叉树。
② 若中序序列与后序序列相反,则或为空树,或为任一结点至多只有右子树的二叉树。
③ 若先序序列与中序序列相反,则或为空树,或为任一结点至多只有左子树的二叉树。
7 线索二叉树
1、引入线索便于查找结点的前驱和后继。
在线索二叉树上遍历消除了递归,也不使用栈。
2、分类:先序线索二叉树、中序线索二叉树、后序线索二叉树。
8 树和森林
1、森林和二叉树的关系及转换
2、树的遍历有2条搜索路径:
① 先根遍历:若树不空,则先访问根结点,然后依次先根遍历各棵子树。
② 后根遍历:若树不空,则先依次后根遍历各棵子树,然后访问根结点。
3、森林的遍历
① 森林的分解:森林中第一棵树的根结点,森林中第一棵树的子树,森林中的其他树。
② 森林的遍历有2条搜索路径:先序遍历、中序遍历。
9 二叉搜索树、二叉平衡树
一、二叉搜索树
1、二叉搜索树的定义。
2、一个无序序列,通过构建二叉搜索树而成为有序序列。
3、平均搜索长度ASL值。
4、插入结点、删除结点。
二、二叉平衡树
1、平衡二叉树的定义。
2、平衡调整操作:LL、RR、LR、RL。
10 哈夫曼树、哈夫曼编码
1、哈夫曼树
指对于一组带有权值的叶结点,构造的具有最小带权路径长度的二叉树。
2、哈夫曼树的构造方法。
3、总结
① 用 n 个叶子结点构造哈夫曼树,共需要 n-1 次合并。
即非叶结点的总数为 n-1,总结点个数为 2n-1。
② 哈夫曼树中没有度为1的结点,因为非叶结点都是两个结点合并的。
而没有度为1的二叉树并不一定是哈夫曼树。
③ 用 n 个叶子结点构造哈夫曼树,形态并不是唯一的。
④ 高度为 h 的哈夫曼树,叶结点的编码最大长度为 h-1。
4、哈夫曼编码思想
将构成电文的每个不同字符作为叶结点,其权值为字符的使用频率,构造哈夫曼树。
结点分支左标识为 "0",右标识为 "1",树中从根到每个叶结点都有唯一的路径,即 "0" 和 "1" 组成的哈夫曼编码。
11 图
1、图
2、无向图
3、有向图
4、无向完全图
5、有向完全图
6、稠密图、稀疏图
7、顶点的度、入度、出度
8、边的权、网图
9、路径、路径长度
10、简单路径、简单回路
11、子图
12、连通图、连通分量
13、强连通图、强连通分量
14、生成树
15、生成森林
12 图的存储及基本操作
1、邻接矩阵
用一维数组存储图中顶点的信息,用矩阵表示图中各顶点之间的邻接关系。
① 无向图的邻接矩阵一定是对称矩阵。
② 有向图的邻接矩阵不一定是对称矩阵。
有向完全图的邻接矩阵一定是对称矩阵。
③ 对于无向图,邻接矩阵的第 i 行非零元素的个数就是第 i 个顶点的度。
④ 对于有向图,邻接矩阵的第 i 行非零元素的个数就是第 i 个顶点的出度。
⑤ 稠密图适合用邻接矩阵存储表示。
2、邻接表
一种顺序存储、链式存储结合的存储方法。对于每个顶点vi,将所有邻接于 vi 的顶点 vj 链成一个邻接表,再将所有邻接表表头放到数组中。
① 若无向图中有 n 个顶点、e 条边,则它的邻接表需 n 个头结点和 2e 个表结点。
② 无向图的邻接表中,顶点 vi 的度恰为第 i 个链表中的结点数。
③ 有向图的邻接表中,顶点 vi 的出度恰为第 i 个链表中的结点数。
④ 稀疏图适合用邻接表存储表示。
13 图的遍历
1、通常有深度优先搜索、宽度优先搜索。前者是递归的过程,后者是非递归过程。
2、两者遍历图的时间复杂度相同,不同之处仅仅在于对顶点访问的顺序不同。
用邻接矩阵存储时,时间复杂度为 O(n^2)
用邻接表存储时,时间复杂度为 O(n+e)
3、深度优先搜索历的空间复杂度为 O(n)
4、树的先根遍历是一种深度优先搜索策略。
树的层次遍历是一种宽度优先搜索策略。
14 图的基本应用
一、图的最小生成树
1、图的生成树不是唯一的。
2、普里姆(Prim)算法的基本思想。
3、克鲁斯卡尔(Kruskal)算法的基本思想。
4、Prim 算法的时间复杂度为 O(n^2),适用于稠密图。
5、Kruskal 算法需对 e 条边按权值排序。若采用堆排序算法:
Kruskal 算法的时间复杂度为 O(eloge),适用于稀疏图。
二、图的拓扑排序
1、拓扑有序序列
AOV 网 G 中的顶点所构成的有序序列,且满足以下条件:
① AOV 网的优先关系与序列的先后关系一致。
② AOV 网中无优先关系的顶点也赋予了一定的先后关系。
拓扑排序:构造拓扑有序序列的过程,序列可能不唯一。
2、若AOV网中所有顶点都在拓扑序列中,则该网不存在回路。
3、拓扑排序的方法。
三、图的关键路径
1、关键路径
AOE 网中从源点到终点的最大长度的路径。
关键路径长度是整个工程所需的最短工期。
关键路径上的活动称为关键活动,要缩短工期,必须加快活动的进度。
2、求关键路径的算法
(1)求AOV网中所有事件的最早发生时间 ve()
(2)求AOV网中所有事件的最迟发生时间 vl()
(3)求AOV网中所有活动的最早发生时间 e()
(4)求AOV网中所有活动的最迟发生时间 l()
(5)找出所有 e()=l() 的活动构成的关键路径。
四、图的最短路径
1、Dijkstra 算法
用于求图中从某个顶点到其他顶点的最短路径,时间复杂度 O(n^2)
也可以重复利用算法,求图中每一对顶点之间的最短路径,时间复杂度 O(n^3)
2、Floyd 算法
用于求图中每一对顶点之间的最短路径,时间复杂度 O(n^3)
15 顺序查找、折半查找
一、顺序查找
1、一种思想比较朴素的比较算法,时间开销大,常用于无序表的查找。
2、时间复杂度为O(n)。对于线性链表,只能进行顺序查找。
二、折半查找
1、这一种有序顺序表的快速查找算法。一次比较就能排除一半的记录。
2、时间复杂度为O(log₂ n)。查找过程可用二叉判定树来描述。
3、查找长度不超过树的高度,若有序表的长度为n,比较次数最多为 ⌊log₂ n⌋+1。
注:在查找中是和关键字进行比较,而不是和数据元素进行比较。
16 B- 树
1、定义
一棵 m 阶 B- 树满足下列特性:
① 结点最多有 m 个孩子。根结点至少有 2 个孩子。
② 结点至少有 ⌈m/2⌉ 个孩子。(除了根结点和失败结点)
③ 失败结点都在同一层。(即叶子结点都在同一层)
2、性质
① 结点最多有 m 个孩子,m-1 个关键字。
② 结点至少有 ⌈m/2⌉ 个孩子,⌈m/2⌉-1 个关键字。(除了根结点和失败结点)
③ 设失败结点总数是s,元素总数是N,则:N=s-1
④ 设有 N 个元素的 m 阶 B- 树的高度是 h,则:h ≤ 1+log⌈m/2⌉ (N+1)/2
3、插入、删除操作
① 插入。分裂条件:关键值个数 > m-1
② 删除。合并条件:关键值个数 < ⌈m/2⌉-1,且借不到(兄弟/双亲/孩子/指针)
17 散列表
1、一般情况下,很容易产生“冲突”现象,即:key1 ≠ key2,f(key1) = f(key2)。
2、常用的散列函数:H(key) = key (mod P),P≤m 且 P 为最大素数。
3、处理冲突的方法
1)闭散列法,也称开地址法:线性探测法、二次探测法、双散列法。
2)开散列法,也称链地址法(略)
18 排序
1、直接插入排序
依次将待排序列中的记录插入到已排序列中,直到全部都排好序。
2、简单选择排序
第 i 趟通过 n-i 次比较,在 n-i+1 个记录中选取关键码最小的记录,并和第 i 个记录交换。
3、冒泡排序
两两比较相邻记录的关键码,如果反序则交换,直到没有反序的记录为止。
4、快速排序
首先选一个轴值,将待排序列分割成两部分,左侧关键码均小于或等于轴值,右侧关键码均大于或等于轴值,然后对这两个部分重复上述过程,直到整个序列有序为止。
5、归并排序
将若干有序序列进行两两合并,直到所有记录都在一个有序序列为止。
6、堆排序
首先将序列调整成堆,堆顶与堆底交换,弹出堆顶。再调整成堆...以此类推,直到只有一个记录为止。
7、各种内排序算法的比较
1、稳定:合并排序、冒泡排序、直接插入排序。
2、不稳定:快速排序、堆排序、希尔排序、简单选择排序。
4/4 MOOC笔记
一、绪论
1-1 基本概念
① 数据:可被计算机识别并加工处理的对象。
② 数据元素:由数据组成的具有一定意义的基本单位。
③ 数据项:组成数据元素的、不可分割的最小单位。
1-2 数据结构
数据结构是指某一数据对象及其中所有元素之间的关系组成。
数据如何组织并存储于计算机中使其能有效运行的方式。
包括数据的逻辑结构、存储结构、对数据的运算。
1)逻辑结构:数据元素间的逻辑关系
根据数据元素关系的特征,可分为四种基本逻辑结构:
a.集合结构,数据元素同属于一个集合,没有关系
b.线性结构,数据元素之间存在一对一的关系
c.树形结构,数据元素之间存在一对多的关系
d.图形结构,数据元素之间存在多对多的关系
四种逻辑结构也可分为两类:线性结构、非线性结构
2)存储结构:数据元素及数据元素之间的关系在计算机内的表示形式
① 顺序存储结构:将逻辑上相关的数据元素依次存储在地址连续的存储空间中
假设有一线性数据结构(a0,a1,a2),每个数据元素占2个存储单元,存储区的起始地址是100,如何存储?
② 链式存储结构:数据元素存储在连续或不连续的存储空间,数据元素之间的关系通过指针域来体现
假设有一线性数据结构(a0,a1,a2),每个数据元素占2个存储单元,存储区的起始地址是100,如何存储?
③ 索引存储结构:建立附加的索引表来标识结点的地址
④ 散列存储结构:将数据元素的关键字与存储位置之间建立散列表
1.顺序存储和链式存储是两种最基本的存储表示方法。
2.存储时不仅保存了数据元素,还保存了数据元素之间的逻辑关系。
3)数据的运算:数据被使用的方式
① 搜索运算:在数据结构中搜索满足一定条件的元素;
② 插入运算:在数据结构中插入新的元素;
③ 删除运算:将数据结构中指定元素删除;
④ 更新运算:将数据结构中指定元素更新为新的元素。
数据结构的三要素:给定数据分析数据元素间的逻辑结构,采取恰当的存储结构,实现数据的运算
4)为什么要学习数据结构
1-3 算法和算法分析
1)什么是算法
算法是对特定问题的求解步骤的一种描述,是指令的有限序列
① 输入:算法有零个或多个输入。
② 输出:算法至少产生一个输出。
③ 确定性:算法的每一条指令都有确切的定义,没有二义性。
④ 可行性:可以通过已实现的基本运算执行有限次来实现。
⑤ 有穷性:算法必须总能在执行有限步之后终止。
2)算法的描述方法
算法可以用自然语言、流程图、伪代码、程序设计语言描述。
当一个算法用程序设计语言描述时,便成为程序。(教材使用C语言描述)
A:算法和程序最显著的区别是什么呢?
Q:算法必须是有穷的,而程序不一定满足有穷性。
比如电脑开机运行中的操作系统,只要整个系统不遭破坏,它将永远不会停止。即使没有作业需要处理,它仍处于动态等待中。所以操作系统只是程序,不是一个算法。
3)算法优劣的衡量标准
① 正确性:执行结果满足预先规定的功能和性能要求。
② 可读性:思路清晰、层次分明、易读易懂。
③ 健壮性:当输入不合法数据时,能做适当处理,不至于引起严重后果。
④ 高效性:执行效率高,占用存储空间少。
1-4 时间复杂度
1)什么是时间复杂度
算法的时间复杂度是程序运行从开始到结束所需的时间。
一般情况下,可以通过程序中的程序步数来衡量算法的时间复杂度。
2)渐近时间复杂度
使用大O记号表示的时间复杂度,也常简称为时间复杂度。
通常用O(1)表示常数计算时间,即算法只需执行有限个程序步。
很多情况下,可以通过一个算法中的关键操作(执行次数最多的程序步)的执行次数来计算时间复杂度,有时也需要同时考虑几个关键操作。
3)最好/最坏/平均时间复杂度
例:在一个有n个元素的数组中查找指定元素,某个搜索算法从第一个元素开始挨个检查。
最好情况:待查元素是第一个元素(查找1次)
最坏情况:待查元素是最后一个元素(查找n次)
平均情况:对第i个元素,从头开始找到它需要进行i次查找,共有n个元素,平均查找次数为 (1+2++n)/n=(n+1)/2
1-5 空间复杂度
算法的空间复杂度是指程序运行从开始到结束所需的存储量,一般按最坏情况来分析。
问题实例的特征是指与问题的具体实例有关的量。
例:对特定个数的元素进行排序,排序就是排序问题的一个实例,元素个数就是该实例的特征。
程序运行所需的存储空间包括两部分:
① 固定部分
这部分空间与所处理数据的大小、个数无关(与问题实例的特征无关)
例:程序代码、常量、简单变量、定长成分的结构变量所占的空间。
② 可变部分
这部分空间大小与算法在某次执行中处理的特定数据的大小、规模有关
例:分别为包含100个元素的两个数组相加,与分别为包含10个元素的两个数组相加,所需的存储空间。
二、线性表
2-1 线性表的定义
一、线性表
线性表是零个或多个数据元素构成的线性序列,记为(a0,a1,...,an-1)
n 为线性表的长度,当 n=0 时线性表为空表。
设线性表(a0,a1,...,ai-1,ai,ai+1,...,an-1)
ai-1 是 ai 的直接前驱,ai+1 是 ai 的直接后继。
a0 没有直接前驱,an-1 没有直接后继,其他元素有且仅有一个直接前驱和一个直接后继。
二、抽象数据类型
2-2 顺序存储
1、顺序存储
指使用连续的存储空间,按照数据元素在线性表中的序号依次存储数据元素。
优点:随机存取,存储空间的利用率高。
缺点:插入删除效率低,存储空间固定。
2、设线性表中第一个元素a0在内存中的存储地址是loc(a0),每个元素占用k个存储单元,则ai在内存的存储地址为:loc(a0)+i*k
3、线性表的顺序表示
2-3 链接存储
一、链表
链表分类:单链表、循环链表、双向链表。
链表不仅需要在数据域(element)存储元素,还需在指针域(link)存储直接后继的地址。
单链表:每个结点只包含一个指针域的链表。最后一个结点的指针域为 NULL,在图中记为 ∧。first 是头指针,指向链表中的头结点。
二、单链表
1、单链表类型定义
2、单链表的插入
3、单链表的删除
三、带表头结点的单链表
四、单循环链表
指将最后一个结点的指针域存储头结点的地址,使得整个单链表形成一个环。
可为单循环链表增加表头结点,构成带表头结点的单循环链表。
五、双向链表
typedef struct duNode{
ElemType element; //数据域
struct duNode * llink; //左指针域,存储直接前驱结点的地址
struct duNode * rlink; //右指针域,存储直接后继结点的地址
}DuNode ,DuList;
q->llink = p->llink;
q->rlink = p;
p->llink -> rlink=q;
p->llink = q;
p->llink->rlink = p->rlink;
p->rlink->llink = p->llink;
free p;
三、堆栈和队列
3-1 堆栈
一、堆栈的基本概念
堆栈(Stack)是限定数据元素的插入和删除操作都在同一端进行的线性结构。
二、堆栈的顺序表示
1、创建一个空堆栈
2、销毁已存在的堆栈
3、清除堆栈中的元素
4、判断堆栈是否已满
5、判断堆栈是否为空
6、获取栈顶元素
7、入栈操作
8、出栈操作
三、堆栈的链接表示
3-2 队列
一、队列的基本概念
队列(Queue)是限定数据元素的插入在表的一端,数据元素的删除在表的另一端的线性结构。
二、队列的顺序表示
三、循环队列
Q:为什么front指向一个不可用的空间,而不是直接指向队头元素?
A:需要一个不可用的空间,来区别队列判空、判满的条件。
四、循环队列的实现
1、创建一个空队列
2、销毁已存在的队列
3、清除队列中的元素
4、判断队列是否为空
5、判断队列是否已满
6、获取堆头元素
7、入队操作
8、出队操作
五、链式队列
3-3 表达式
1、表达式的概念
中缀表达式:操作符在两个操作数之间的表达式。示例:a+b
计算的顺序由界符、操作符优先级决定。
后缀表达式:操作符在两个操作数之后的表达式。示例:ab+
计算的顺序只取决于操作符的扫描顺序。
2、算法的堆栈实现
① 从左往右顺序依次扫描:
若当前扫描元素是操作数,则将操作数压进栈;
若当前扫描元素是操作符,则弹出两个操作数,并执行操作符的运算,然后将结果进栈;
② 当表达式扫描结束,弹出栈顶数据,该数据即为计算结果。
例:642-/32+ = 6/(4-2)+32 = 9
3-4 递归
直接递归:函数的实现过程中出现了对自身的调用。
间接递归:函数调用形成了一个环状调用链。
例:函数A的实现过程中调用了B,而B的实现过程中又调用了A。
递归程序空间需求和时间需求都较高,建议采用循环迭代(非递归)方法。
四、数组
4-1 数组的基本概念
一、数组的定义
数组是下标index和值value组成的偶对的集合。
例1:int one[5]={5, 6, 4, 2, 7};⇒ {(0, 5), (1, 6), (2, 4), (3, 2), (4, 7)};
例2:int one[2][3]={{0, 1, 2}, {3, 4, 6}};⇒ {(<0, 0>, 0), (<0, 1>, 1), (<0, 2>, 2), (<1, 0>, 3), (<1, 1>, 4), (<1, 2>, 6)};
二、数组的顺序存储
三、三维数组的实现
4-2 对称矩阵
在 n×n 的矩阵A中,若a[i][j]=a[j][i],则称其为 n 阶对称矩阵。
只存储上三角(或下三角)中的元素(包括对角线上的元素),需要n(n+1)2个元素的存储空间,提高了存储效率。
4-3 稀疏矩阵
一、稀疏矩阵的定义
矩阵中非零元素数量占元素总数的比例称为矩阵的稠密度。
稠密度小于5%的矩阵称为稀疏矩阵,稀疏矩阵中零元素的分布没有规律。
为了节省存储空间,对稀疏矩阵可以只存储非零元素。
稀疏矩阵常出现于大规模集成电路设计、图像处理等领域。
二、稀疏矩阵的顺序存储
三、稀疏矩阵的转置
1、方法一
步骤1:依次访问A的行三元组表中各个三元组,交换元素行列号。
步骤2:将行三元组表中的三元组按照行下标值从小到大重新排序。
2、方法二
步骤1:找到列下标 j=0的所有三元组<i,0,ai0>,交换元素行列号。
步骤2:找到列下标 j=1的所有三元组<i,1,ai1>,交换元素行列号。
. . .
步骤n:找到列下标 j=n-1的所有三元组<i,n-1,an-1>,交换元素行列号。
四、快速转置算法
五、树和二叉树
5-1 树
一、树的定义
树是包括n个元素的集合D,R是D中元素的序偶集合。若D为空,则为空树;否则,R满足如下要求:① 如果树不为空,则树的根结点是唯一的。② 根结点没有前驱,其它结点均有唯一前驱。
二、树的基本术语
结点(node):树中的元素。根结点和它的子树根之间形成边。
路径(path):从某个结点沿边可到达另一结点,则称两点间存在一条路径。
双亲(parent):若结点有子树,那么该结点称为子树根的双亲。
孩子(child):某结点子树的根称为该结点的孩子。
兄弟(sibling):有相同双亲的结点互为兄弟。
后裔(descendant):某结点子树上的任何结点都是该结点的后裔。
祖先(ancestor):从某结点到根结点路径上的所有结点都是该结点的祖先。
结点的度(degree):结点拥有的子树数。
叶子(leaf):度为零的结点。
分支结点(branch):度不为零的结点。
树的度:树中各结点度的最大值。
结点的层次:根结点层次为1,其余结点层次等于其双亲结点层次加1。
树的高度:树中结点的最大层次。
无序树:树中结点的各树之间的顺序无关,可以交换位置。
有序树:树中结点的各棵子树从左到右顺序相关,不可以交换位置。
森林:0棵或多棵不相交的树组成森林。
5-2 二叉树
一、二叉树的定义及性质
1、二叉树的定义
二叉树(binary tree)是结点的有限集合,该集合要么为空集,要么由一个根和两个互不相交的左、右子树的二叉树组成。
二叉树中结点的子树要区分左、右子树,即使只有一棵子树。二叉树的每个节点最多只能有2棵子树。
2、二叉树的性质
① 二叉树的第 i 层上至多有 2^(i-1) 个结点,i≥1。
② 高度为 h 的二叉树上至多有 2^h-1 个结点,h≥0。
③ 包含 n 个结点的二叉树高度最矮为 ⌈log₂(n+1)⌉,最高为n。
④ 二叉树中,若叶结点数量为n0,度为2的结点数量为n2,则有:n0=n2+1。
二、特殊二叉树
1、满二叉树
高度为h,且有2^h-1个结点的二叉树。
2、完全二叉树
① 只有最下面两层中结点的度可以小于2。
② 叶结点均依次集中在靠左的若干位置上。
3、扩充二叉树
除叶结点外,其余结点都必须有两个孩子。
满二叉树一定是完全二叉树,也是扩充二叉树。
三、二叉树的ADT
四、二叉树的存储表示
五、二叉树的基本运算
1、创建一棵空二叉树
2、创建新结点
3、返回树的根结点
4、构建一棵二叉树
5-3 二叉树的遍历
一、二叉树遍历的基本概念
二叉树的遍历:对二叉树中的每个结点访问且仅访问一次的操作。
先序遍历(VLR):先访问根结点,再遍历左子树,最后遍历右子树。
中序遍历(LVR):先遍历左子树,再访问根结点,最后遍历右子树。
后序遍历(LRV):先遍历左子树,再遍历右子树,最后访问根结点。
二、先序、中序、后序遍历
三、二叉树的层次遍历
① 从上到下、从左到右逐层访问二叉树每一个结点。
② 每个节点访问且仅访问一次。
四、二叉树遍历的相关性质
1,给定一棵二叉树,可以得出先序、中序、后序和层次遍历序列。
2,已知二叉树的先序遍历和中序遍历序列,可以唯一确定一棵二叉树。
3,已知二叉树的后序遍历和中序遍历序列,可以唯一确定一棵二叉树。
4,已知二叉树的先序遍历和后序遍历序列,无法唯一确定一棵二叉树。
五、二叉树遍历的应用实例
1、计算二叉树的结点总数量
2、清空二叉树
5-4 树和森林
一、树转换为二叉树
连线:将树中具有兄弟关系的结点从左到右依次连线;
去线:仅保留结点最左孩子的连线,去掉其余孩子的连线;
整形:调整为标准形状的二叉树。
二、森林转换为二叉树
将森林中的每一棵树转换为对应的二叉树,然后根结点依次并入右子树。
三、二叉树转换为树或森林
整形:将所有结点左孩子连线调整为垂直、右孩子连线调整为水平;
连线:将水平线上的第一个结点的父节点,与其他的结点进行连线;
去线:去除水平连线;
整形:调整树的形状。
四、树和森林的存储表示
① 多重链表表示法(链接结构)
② 孩子兄弟表示法(链接结构)
③ 三重链表表示法(链接结构)
④ 双亲表示法(顺序结构)
⑤ 带右链的先序表示法(顺序结构)
五、树和森林的遍历
1、先序遍历(深度方向)
2、中序遍历(深度方向)
3、后序遍历(深度方向)
4、层次遍历(宽度方向)
5-5 堆和优先权队列
一、堆的概念及存储表示
1、什么是堆
从逻辑结构上看,一个大小为 n 的堆是一棵包含 n 个结点的完全二叉树,根结点称为堆顶,包含如下两类:
① 最小堆:树中每个结点的数据都小于或等于其孩子结点,堆顶存储的数据是整棵树中最小的。
② 最大堆:树中每个结点的数据都大于或等于其孩子结点,堆顶存储的数据是整棵树中最大的。
2、堆的存储表示
二、建堆运算
1、向下调整(AdjustDown)
算法思想:以最小堆为例,从最后一个叶子的双亲反方向直到根结点,依次对其中的每一个结点执行向下调整操作。步骤如下:
① 若该结点小于等于其最小的孩子,则本轮调整结束;否则执行步骤 ②
② 将该结点与最小孩子交换,然后继续以该结点为考查对象,再次执行步骤 ①
2、向上调整(AdjustUp)
算法思想:设新元素插入在最小堆元素序列的尾部。从新元素开始,自底向上,与父结点元素进行大小比较。若父结点元素大于孩子结点元素,则进行交换,直到其父结点元素不大于孩子结点元素。
三、优先权队列
1、什么是优先权队列
一种具有如下特性的数据结构:元素加入的次序无关紧要,但每次取元素时,都只取具有最高优先级的元素。
2、优先权队列的实现
5-6 哈夫曼树及哈夫曼编码
一、树的路径长度
文本压缩:将文本重新编码,节省不必要的空间,需支持反向解压(解码)
字符编码:可以等长(如 ASClI 编码等),也可以不等长(如哈夫曼编码)
树的内路径长度:除叶结点外,从根到其他结点的路径长度和。
树的外路径长度:从根结点到树中所有叶子结点的路径长度和。
定理:扩充二叉树的外路径长度 E,内路径长度 I,非叶结点个数 n,则有 E=I+2n 。
叶结点的加权路径长度:指其路径长度与权值的乘积。
树的加权路径长度:所有叶结点的加权路径长度之和,记为 WPL = Σ wl 。
每一个叶结点表示一个字符;
叶结点权值指对应字符在文本中的出现频率;
叶结点的路径长度表示对应字符的编码长度;
WPL表示的是文本转编码之后的总编码长度。
二、哈夫曼树和哈夫曼算法
哈夫曼树是扩充二叉树,且非叶节点的权值等于左右孩子的权值之和。
三、哈夫曼编码
六、集合和搜索
6-1 集合的抽象数据类型
一、基本概念
数据结构意义上,集合通常是动态的。在集合中可以插入和删除元素,因而称为动态集。
二、 集合的抽象数据类型
三、集合的表示形式
集合可以用线性表、搜索树、散列表表示。
6-2 顺序表搜索
6-3 二分搜索
6-4 平均搜索长度分析
一、平均搜索长度
1、分析一个搜索算法的时间复杂度通常分为搜索成功、搜索失败两种情况。
2、为了确定指定关键字值记录在表中的位置,需要进行关键字值间的比较,这些比较次数的期望值称为搜索算法的平均搜索长度(ASL)。
二、无序表的顺序搜索
1、成功搜索的平均搜索长度:ASL = (n+1)/2
2、搜索失败的平均搜索长度:ASL = n
三、有序表的顺序搜索
1、成功搜索的平均搜索长度:ASL = (n+1)/2
2、搜索失败的平均搜索长度:ASL = 2+n/2
四、二分搜索的平均搜索长度分析
可以建立一棵二叉判定树来模拟对半搜索执行过程。
二叉判定树上的搜索定理:在成功搜索的情况下,算法比较次数不超过 ⌊log2 n⌋ +1。在失败的搜索情况下,算法比较次数为 ⌊log2 n⌋ 或 ⌊log2 n⌋ +1 。
七、搜索树
7-1 二叉搜索树
一、二叉搜索树的基本概念
1、定义:设结点由关键字值表征,所有结点的关键字值各不相同。二叉搜索树具有下列性质:
① 左(右)子树上所有结点的关键字值均小(大)于根结点;
③ 左、右子树也分别是二叉搜索树。
2、性质:若中序遍历一棵二叉搜索树,关键字值递增排列。
3、二叉搜索树类型实现
4、二叉搜索树搜索操作
二、二叉搜索树的插入操作
1、在二叉搜索树上插入新结点
2、从空树开始构造二叉搜索树(同理)
3、二叉搜索树插入操作
三、二叉搜索树的删除操作
1、删除叶结点。2、删除有一个孩子的结点。3、删除有两个孩子的结点。
四、二叉搜索树搜索操作的时间复杂度
7-2 二叉平衡树
一、基本概念
1、二叉平衡树(AVL树):具有下列性质的二叉搜索树:
① 其根的左、右子树高度差不超过1。② 其根的左、右子树都是二叉平衡树。
2、结点的平衡因子:该结点的左子树高度减去右子树高度之差。
二、二叉平衡树的插入
1、先按二叉搜索树的插入方法插入结点以保持排序性;
2、然后判断平衡性是否被破坏,进而决定是否需要调整平衡;
3、若平衡性被破坏,找到要调整的最小子树,调整其平衡性。
三、最小子树S上的平衡调整方法
① LL(RR)类型,即新结点插入s的左(右)子树的左(右)子树上,则采用单旋转方法;
② LR(RL)类型,即新结点插入s的左(右)子树的右(左)子树上,则采用双旋转方法。
7-3 B-树
一、m叉搜索树
1、m叉搜索树的定义
图中的方块代表空树,也称失败结点,因为这是当搜索不到关键字值时到达的子树。
失败结点中不包含元素,失败结点不是叶子结点。
2、内搜索和外搜索
内搜索:当集合足够小,可以驻留在内存中时,相应的搜索方法。
外搜索:如果文件很大,计算机内存容不下时,必须存放在外存。在外存中相应的搜索方法。
内存中集合用二叉平衡树表示。外存中集合用一种特殊的m叉搜索树——B-树表示。
典型的磁盘存取时间是1ms-10ms,典型的内存存取时间是10ns-100ns。
内存的存取速度比磁盘快1万至百万倍,设法减少磁盘存取操作是外搜索应充分考虑的问题。
3、m叉搜索树的性质
性质1:高度为h的m叉搜索树中最多有 m^h-1 个元素。
性质2:含有N个元素的m叉搜索树高度在 logm(N+1)~N 之间。
二、B-树的定义及性质
1、定义
一棵 m 阶 B- 树满足下列特性:
① 根结点至少有2个孩子(根结点可以只有一个元素);
② 除根结点和失败结点都至少有 ⌈m/2⌉ 个孩子(保证B-树不会退化成单支树);
③ 所有失败结点均在同一层上。(考虑平衡性)
由定义可以得到:
① 一个结点最多有m个孩子,m-1个关键字;
② 除根结点和失败结点都至少有 ⌈m/2⌉ 个孩子,⌈m/2⌉-1个关键字;
③ 失败结点的双亲是叶结点。
2、性质
① 设B-树的失败结点总数是s,元素总数是N,则:N=s-1
② 设有N个元素的m阶B-树的高度是h,则:h ≤ 1+log⌈m/2⌉ (N+1)/2
三、B-树的搜索
1、搜索的过程是一个顺指针查找结点,和在结点的关键字中搜索交叉进行的过程。
2、B-树主要做文件的索引,因此搜素涉及外存的存取,包含两种基本操作:
① 在B-树中找结点。需执行的磁盘访问次数 ≤ 1+log⌈m/2⌉ (N+1)/2。
② 在结点中找关键字。B-树的每个结点可以看成一个有序表,在结点中的搜索是在内存中,可以采用顺序搜索、二分搜索等算法。
四、B-树的插入
例:在4阶B-树中插入新元素59
m阶B-树每个结点的关键字数为 ⌈m/2⌉-1~m-1,即 1~3。
1、插入元素59后关键字数大于3(上溢出)。
2、将第 ⌈m/2⌉ 个关键字提升,并分裂结点。
3、若调整后父节点关键字数大于3,继续调整。
五、B-树的删除
例:在4阶B-树中删除元素35
m阶B-树每个结点的关键字数为 ⌈m/2⌉-1~m-1,即 1~3。
1、用右子树最小元素39替代元素35。
2、删除元素39,关键字数小于1(下溢出)。
3、向兄弟结点借元素47,交换元素43和47(调整顺序)。
八、散列表(鸽)
九、图
9-1 图的基本概念
一、相关定义
1、图(Graph):是数据结构 G=(V,E),V是结点的有限非空集合,E是边的有限集合。
2、图中的结点又称为顶点。
3、如果图中边的偶对是有序的,则该图称为有向图。
4、用<u,v>表示一条有向边,u为始点(尾),v为终点(头)。
5、如果图中边的偶对是无序的,则该图称为无向图。
二、基本术语
1、自回路:无向边 (u,u) 或有向边 <u,u>。
2、多重图:两个顶点间允许有多条相同边的图。
3、完全图:如果一个图有最多的边数,称为完全图。
包含n个顶点的无向完全图有 n(n-1)/2 条边。
包含n个顶点的有向完全图有 n(n-1) 条边。
4、邻接与关联:如果 (u,v) 是无向图中的一条边,则称顶点 u、v 邻接,并称 (u,v) 与 u、v 相关联。
5、子图:图 G=(V,E) 的一个子图是图 G'=(V',E'),其中 V'⊆V,E'⊆E。
6、路径:图G中,一条从 s 到 t 的路径是存在一个顶点序列 (s,v1,v2,...,vk,t),使得 (s,v1),(v1,v2),...,(vk,t) 都是图G中的边。
7、路径长度:指路径上边的数目。
8、简单路径:除起点和终点,路径上其余顶点各不相同。
9、回路:起点和终点相同的简单路径。
10、连通图:任意两个顶点连通的无向图。
11、连通分量:无向图的极大连通子图。
注:①每个连通分量必须包含其顶点之间的所有边。
② 如果某个连通子图加上一个顶点后,仍是连通的,则它不是连通分量。
12、强连通图:任意两个顶点互相存在路径的有向图。
13、强连通分量:有向图的极大强连通子图。
14、顶点的度:与该顶点相关联的边的数目。
入度:有向图顶点v的入度指以v为头的边的数目。
出度:有向图顶点v的出度指以v为尾的边的数目。
15、生成树:无向连通图的生成树是一个极小连通子图。它包含图中所有n个顶点,但只有刚好构成一棵树的 (n-1) 条边,再加上1条边将构成回路。
16、网:在图的每条边加上一个数字作为权值,这种带权的图称为网。
三、图的抽象数据类型
9-2 图的存储结构
一、邻接矩阵表示法
1、邻接矩阵表示法
2、图的邻接矩阵实现
二、邻接表表示法
1、邻接表表示法
2、图的邻接表实现
9-3 图的遍历
图的遍历:给定一个顶点v,从v出发对图中所有顶点访问且仅访问一次。
1、深度优先搜索(DFS)遍历
2、DFS 算法实现
3、宽度优先搜索(BFS)遍历
4、BFS 算法实现
9-4 拓扑排序
一、顶点活动网络(AOV网)
顶点代表活动,有向边表示活动之间领先关系的有向图。
二、拓扑排序
将AOV网中顶点排成一个线性序列,满足:若在网中 vi 到 vj 有路径,则 vi 必定在 vj 之前。
三、拓扑序列
AOV网中顶点的线性序列,使得若在网中 vi 领先于 vj,则在线性序列中 vi 是 vj 的前驱结点。
四、拓扑排序算法
1、在图中找一个入度为零的顶点将其输出。
2、从图中删除该顶点及其所有出边。
3、重复 1、2,直到所有顶点都输出(此时得到拓扑序列),或再也没有入度为零的顶点(此时存在有向回路)。
9-5 关键路径
一、基本概念
AOE网在正常(无环)情况下:
1、源点:只有一个入度为零的点,表示工程开始。
2、汇点:只有一个出度为零的点,表示工程结束。
3、关键路径:从源点到汇点的最长路径的长度。
4、关键活动:关键路径上的边代表的活动。
二、关键路径求解过程
9-6 最小代价生成树
一、基本概念
1、无向连通图的生成树是一个极小连通子图,它包括全部顶点,且有尽可能少的边。
2、遍历连通图得到一棵生成树。生成树不是唯一的,采用不同的遍历,得到不同的生成树。
3、最小代价生成树:对于带权的连通图(网),使得各条边权值之和最小的生成树。
二、普里姆算法
三、克鲁斯卡尔算法
(1)在 E 中选择一条代价最小的边 (u,v),并将其从E中删除
(2)若在 E' 中加入 (u,v) 后未形成回路,则将其加进 E' ,否则重复步骤(1)
(3)重复步骤(2),直至 E' 中包含 n-1 条边为止。
9-7 单源最短路径
1、迪杰斯特拉(Djikstra)算法:一种最常见的求单源最短路径算法。
这里所说的最短路径是指路径上边的权值之和最小。
2、单源最短路径问题:给定带权的有向图和源点v0,求从 v0 到其余点的最短路径。