第一章、绪论
- 数据结构是一门研究非数据计算的程序设计问题中计算机的操作对象,以及它们之间关系,操作等的学科。
- 数据结构包括数据的逻辑结构,存储结构,运算这三方面的内容。
- 逻辑结构:①树形结构 ②图形/网状结构 ③集合 ④线性结构,其中①②③可称为非线性结构。
- 存储结构:①顺序结构 ②链式结构。
- 运算:①插入 ②删除 ③修改 ④查找 ⑤排序。
- 数据的基本单位是数据元素,数据的最小单位是数据项。
- 线性结构元素之间存在一对一关系,树形结构一对多,图形结构多对多。
- 算法的时间复杂度取决于问题的规模和待处理数据的初态。
第二章、线性表
- 在单链表中,增加头节点的目的是方便运算的实现。
第三章、栈和队列
- 栈和队列是操作受限的线性表
- 循环队列的引入,是为了克服假溢出现象。
第四章、数组和广义表
- 稀疏矩阵一般的压缩方法有两种:①三元组(数据,行,列) ②十字链表。
- 对一个稀疏矩阵转置不仅要交换行标和列标,还要按从小到大的顺序排列好。
- 广义表的表尾是除表头元素外其它元素组成的广义表。
第五章、树和二叉树
-
常见满二叉树的深度的节点总数:1,3,7,15,31,63,127。
-
第k层的节点最多有:2 k − 1 ^{k-1} k−1个节点。
-
有n个节点的完全二叉树的深度为: ⌊ l o g 2 n ⌋ + 1 \lfloor log_2n \rfloor +1 ⌊log2n⌋+1
-
编号为i的节点的左孩子为2i,右孩子为2i+1。
-
完全二叉树中度为1的节点个数为0或1。
-
因为每个节点都有一条“入度”边,根节点除外,所以节点数n=x边数+1,从而n 0 _0 0+n 1 _1 1+n 2 _2 2=n 1 _1 1+2n 2 _2 2+1 => n 0 _0 0=n 2 _2 2+1.
-
树 ==> 二叉树:根节点只连长子,断开与其它孩子的链接,长子连其它孩子,即“左孩子,右兄弟”。可得结论:森林中有n个非终端节点(除叶子外的节点),对应二叉树有n+1个节点右指针链域为空。 推导:因为非终端节点的孩子中必有一个幺子,幺子没有更小的兄弟,右链必空,再加上森林最后一棵树的根节点也再无兄弟,所以要+1。
-
二叉树 ==> 树:右子树链接的是兄弟,左子树连的是孩子,复原即可。
-
树的先根 == 对应二叉树的先根。
-
树的后根 == 对应二叉树的 中根。
-
Huffman哈夫曼树:也称最优二叉树,***带权路径***最短树,树的带权路径长度WPL(Weighted path length)为各叶子节点的带权路径长度之和。
WPL= ∑ w l \sum{wl} ∑wl。
-
路径长度:两节点之间边的个数。
第六章、图
连通的概念
- 对无向图:
- 两点间有路线,则称此两点连通。
- 若图G任意两点连通,则称G为连通图。
- 若G的子图G’连通,则称G’为连通分量==子图。
- 极大连通子图称为连通分量。
- 对有向图:
- 若图G任意两点连通,则称G为强连通图。
- 极大连通子图:强连通分量。
- 极小连通子图:生成树。
- 极大概念:包含尽可能多的边。
- 极小概念:删除任意一条边后就不连通了。
存储与遍历:
- 图的存储分为矩阵和表。
- DFS,BFS遍历同一张图复杂度相同,DFS深度需要递归借用栈,BFS广度需要借用队列。
- 遍历矩阵时间复杂度:O(n 2 ^2 2)。
- 遍历表时间复杂度:O(n+e)。
- 空间复杂度都是:O(n),因为都借用了栈或队列。
关键路径
-
拓扑排序:
- 在有向图中选一个没有前驱的节点(即入度为0)且输出之。
- 删除该节点,且以该节点为尾的弧。
重复上述步骤,若能够输出所有节点,则图中无环,否则图中存在环。
拓扑排序时间复杂度O(n+e)。
-
有向无环图DAG:用拓扑排序判断有无环。分为AOV(用顶点表示活动),AOE(用边表示活动)。
-
AOE:顶点叫做事件。
-
事件的最早开始时间:因为前面所有事件全都完成后方可进行本事件,所以在必须完成事件中,加上到达本事件的活动的时间,可得一个本事件开始时间,在其中取最大值,即得最早时间。
eg:小明喝完牛奶,小红画完妆后,我们才能出门,小明喝完牛奶是8:00,小红化完妆是9:00,取最大值9:00出门。
-
事件的最晚开始时间:后方所有节点的最晚开始时间,减去本节点到达它所需时间,可得后方节点对本节点的最晚要求,在其中取最小值,即得最晚时间。
eg:班主任要我8:00到教室,英语老师要我9:00到教室,我到教室需要30分钟,即班主任要求我最晚7:30出门,英语老师要求我最晚8:30出门,取最小值7:30出门。
-
最早时间 == 最晚时间 的事件称为关键事件,关键事件组成的路径称为关键路径,关键路径并不唯一,所以缩短关键路径上某一个事件不一定能缩短工程时间,因为此事件不一定处于关键路径的交集中。eg:关键路径A:0–>1–>2–>5–>7,B:0–>1–>3–>5–>7,缩短了3的时间不一定能缩短时间,必须缩短AB交集0157的时间。
-
生成树
- 找到生成树的算法:
- Prim算法,时间复杂度O(n 2 ^2 2),适用于边多的,从点找,找点邻接表中权值最小的边。
- Kruskal算法,时间复杂度O(elog(e)),适用于边少的,从边找,找所有边中权值最小的边。
最短路径
- 从某个顶点到其它点的最短路径:
- Dijkstra迪杰斯特拉算法,时间复杂度O(n 2 ^2 2)。
- 找到每对顶点间的最短路径:
- 对每对顶点使用Dijkstra算法,时间复杂度O(n 3 ^3 3)。
- Floyd弗洛伊德算法,时间复杂度也为O(n 3 ^3 3)。
第七章、查找
-
查找表是由同一类型的数据元素构成的集合。
-
对查找表的常见操作:
- 查找某个元素是否在表中。
- 检索某个特定元素的各种属性。
- 插入某个元素。
- 删去某个元素。
静态查找表:a b,仅仅是查找。
动态查找表:a b c d,不仅是查找,找到了可执行删除,找不到可执行插入。
静态查找表
顺序查找
- 优点:算法简单,顺序和链式存储均可。
- 缺点:当n很大时,ASL(Average Search Length)平均查找长度很大。
- 查找性能:ASL= n + 1 2 \frac{n+1}2 2n+1。第1个元素查找成功1次,第n个元素查找成功n次,求和之后再除去n个元素,平均要查找这么多次。
折半查找
- 前提:顺序存储,且有序。
- 二叉判定树:类似于完全二叉树,其高度为 ⌊ l o g 2 n ⌋ \lfloor log_2n \rfloor ⌊log2n⌋+1。
- 查找性能:ASL= n + 1 n \frac{n+1}n nn+1log 2 _2 2(n+1)-1,当n较大时,可近似为log 2 _2 2(n+1)-1。
静态树表的查找
-
当元素的查找不是“等概率”的时候引入静态树表。
-
当静态二叉树的PH(带权内路径长度,与哈夫曼树的带权路径长度区分)最小时,称为最优查找树。
PH= ∑ w h \sum wh ∑wh。
-
与最优查找树PH近似的树称为,次优二叉树。
-
查找性能:次优二叉树的ASL和lon 2 _2 2n成正比。
索引顺序表的查找
- 分块有序,块内无序。索引表记录块内最大关键字,以及块的起始地址。
- 查找:先查找所在块(可选顺序查找,折半查找),再在块内进行顺序查找。
动态查找表
二叉排序树及平衡二叉树
- 二叉排序树:将待查找序列排成树,比根小的放在左子树,比根大的放在右子树。
- 查找性能:最好情况与折半查找相同,与log 2 _2 2n成正比。最差情况变成单枝树,与顺序查找相同。平均查找长度与log n成正比。
- 故为解决这个问题,发明了平衡二叉树。
- 平衡二叉树:又称AVL树,每个节点的平衡因子为-1或0或1。在AVL树上查找的时间复杂度为O(log n)。
- 平衡因子:左子树深度 - 右子树深度。
- 树的平衡化:不平衡的树分为LL,LR,RR,RL型。
B-树和B+树
非考试重点,略。
键树
非考试重点,略。
哈希表
-
哈希表(散列表):既是一种存储形式,又是一种查找方法。
-
哈希函数:在记录的关键字和它的地址间,建立一个确定的对应关系,这个对应关系称为哈希函数。
-
同义词:不同的关键词,Hash过后地址相同。
-
冲突:不同关键词,哈希地址相同。
-
构造哈希函数:
-
直接定址:Hash(k)=ak+b
-
数字分析
-
平方取中
-
折叠法
-
除留余数法:Hash(k)=k % p , p<=m, m为哈希表长。
p的选取:一般选p为质数,或不包含小于20的质因数的合数。
-
随机数法
-
-
处理冲突:
- 开放定址法:Hash’(k)=(Hash(k)+d)% m
- 线性探测再散列,d=1,2,3,…m-1
- 二次探测再散列,d=1,-1,4,-4,9,-9…k 2 ^2 2,k<=m/2
- 伪随机探测再散列,d=随机数序列
- 再哈希法:用另一个哈希函数处理冲突的关键字,可有效应对聚集,但增加了计算的时间。
- 链地址法:也称拉链法,对冲突的同义词,用链表存储。
- 建立公共溢出区
- 开放定址法:Hash’(k)=(Hash(k)+d)% m
-
查找性能:与关键字个数无关,只与①哈希函数 ②处理冲突的方法 ③哈希表的装填因子有关。
第八章、排序
- 根据存储器分类,可分为内部排序和外部排序,外部排序是指待排序记录的数量很大,以致内存一次不能容纳全部记录,在排序过程中尚需对外存进行访问的排序过程。
- 根据结果是否遵循原次序,可分为稳定排序和不稳定排序。
- 根据是否基于比较,可分两类,不基于比较和基于比较的排序。
- 基于比较的算法,可分为插入排序,交换排序,选择排序,归并排序。
- 不基于比较的算法,如基数排序。
插入排序
- 插入排序未借助其它结构,或者递归,所以空间复杂度均为O(1)。
- 希尔排序的复杂度跟增量的选择有关,一般选择增量为长度的一般。
最好 | 最坏 | 平均 | 稳定 | |
---|---|---|---|---|
直接插入 | n | n 2 ^2 2 | n 2 ^2 2 | √ |
折半插入 | n | n 2 ^2 2 | n 2 ^2 2 | √ |
希尔排序 | depend | depend | n 1.3 ^{1.3} 1.3 | 不稳 |
交换排序
- 快速排序需要借助栈来执行递归操作,形成一棵“排序树”,树高为log 2 _2 2n+1,所以牺牲了空间。
- 快速排序是冒泡的改进算法,最坏情况是待排序列已然有序。
最好 | 最坏 | 平均 | 空间 | 稳定 | |
---|---|---|---|---|---|
起泡排序 | n | n 2 ^2 2 | n 2 ^2 2 | 1 | √ |
快速排序 | nlog n | n 2 ^2 2 | nlog n | log 2 _2 2n | 不稳 |
选择排序
最好 | 最坏 | 平均 | 空间 | 稳定 | |
---|---|---|---|---|---|
简单选择 | n 2 ^2 2 | n 2 ^2 2 | n 2 ^2 2 | 1 | 不稳 |
堆排序 | nlog n | nlog n | nlog n | 1 | 不稳 |
归并排序
- 归并排序第一次将每两个归为一组排序,第二次将四个归为一组排序…
- 实现归并需要和待排记录等数量的辅助空间。
最好 | 最坏 | 平均 | 空间 | 稳定 | |
---|---|---|---|---|---|
归并排序 | nlog n | nlog n | nlog n | n | √ |
总结
- 简单排序:插入排序(除了希尔),起泡,简单选择。其它排序都是在此基础上改进的复杂排序。
- 不稳定:希尔,快速,简单选择,堆。
- 需空间:归并 > 快速。
- 常用的高效排序:快速,堆,归并。