树
- 树的存储结构
- 双亲表示法
- 孩子表示法
- 孩子兄弟表示法
- 二叉树
- 满二叉树
- 完全二叉树
- 二叉树性质
- i i i层有 2 i − 1 2^{i-1} 2i−1个结点
- 深度为 k k k的二叉树至多有 2 k − 1 2^k-1 2k−1个结点
- 度为2的结点数 + 1 = 叶子结点数
- n n n个结点的完全二叉树深度为 ⌊ log 2 n ⌋ + 1 \lfloor \log_2n\rfloor+1 ⌊log2n⌋+1
- 按层序编号,子结点是父结点的2倍或2倍+1
- 二叉树存储结构
- 顺序存储:补齐为完全二叉树,层序编号为位置,补的位置填NULL
- 二叉链表:左孩子指针,数据,右孩子指针
- 遍历二叉树:前、中、后序遍历,根节点的位置;层序遍历
- 建立二叉树:将二叉树扩展为全部有左右孩子,按照前(中、后)序遍历序列输入
- 线索二叉树构建:将扩展补得结点添加指针,左孩子指向前驱,右孩子指向后继
- 树、森林、二叉树转换
- 树转换为二叉树:连兄弟,留第一个孩子
- 森林转换为二叉树:先转为多个二叉树,后一棵的根结点是前一棵的右孩子
- 二叉树转换为树:连孩子,去兄弟
- 赫夫曼树:带权路径长度WPL最小的二叉树(最优二叉树)
- 构建:叶子结点的权值从小到大排列,取前两个组一棵树,左小右大,组成后加入原序列,在进行组建和放回,直到完成
- 赫夫曼编码:按使用频率(权重)构建一棵赫夫曼树,左0右1
图
有向图 无向图
- 存储结构
- 邻接矩阵:n*n的表,有链接就有数据
- 邻接表:链表数组,每个链表存相应链接的结点(有向图有逆邻接表)
- 十字链表:有向图的结点和边,结点有数据、第一个入边、第一个出边,边有起点、终点、起点相同的下一条边、终点相同的下一条边
- 邻接多重表:无向图结点和边,结点有数据、第一条边,边有A结点和A结点下一条边,B结点和B结点下一条边
- 边集数组:一个顶点数组,一个边数表(边的序号,起点,终点权重)
- 图的遍历
- 深度优先:递归找下一个结点的第一条边,回溯补全(适合目标明确)
- 广度优先:每个邻接点都遍历,再下一层;队列,邻接点不断入队,直至每个点都循环(适合不断扩大遍历范围时找最优解)
- 最小生成树(连通网,权值和最小)
- Prim算法:从一个点开始找距离最近且不在已知范围内的邻接点
- Kruskal克鲁斯卡尔算法:边的权重有小到大依次加入,加入时检查是否构成环路,直到边全部遍历
- 最短路径:一个点到另一个点,权值之和最小
- Dijkstra迪杰斯特拉算法:从起点开始,逐步找距起点距离最近的点,直至全部遍历
- Floyd弗洛伊德算法(所有顶点之前的最短距离):矩阵计算从每个点中转的最短距离
- 拓扑排序:优先关系的网
- 关键路径:权重最大的一条路
查找
- 顺序表查找算法:挨个查找,可以设置哨兵优化
- 有序表查找:
- 折半查找(加法除法)
- 差值查找:按比例选中间点(四则运算)
- 斐波那契查找(加减)
- 线性索引查找:创建一个查找表,存有关键码和指向记录的指针
- 稠密索引:每个记录对应一个索引值,太大就不行
- 分块索引:存有最大关键码,数量,以及块首指针
- 倒排索引:次关键码和记录表号
- 二叉排序树(二叉查找树)(方便插入和删除):左小右大
- 平衡二叉树(AVL树):左右子树高度差不过1,插入新结点,根据平衡引子左右旋
- 多路查找树(B树)(为了减少内外存交互)
- B树:一个结点多数据多子树,叶子在同一层
- B+树(方便遍历):所有叶子结点包含所有关键字,且按顺序链接;所有分支结点可以看做索引,具体数据在叶子中,且结点保存叶子中最大关键字
- 哈希表:面向查找的存储结构,将关键字进行处理后,得到地址
- 构造哈希表
- 直接定址法:线性函数;查找表小 且 连续
- 数字分析法:取一段;长 且 有一段均匀分布(手机号后四位)
- 平方取中法:平方后取中间几位;不太长 且 不知道分布
- 折叠法:每几位求和;长 且 不知道分布
- 除留余数法:取某数p的模,p接近表长的最小质数或不包含小于20质因子的合数
- 随机数法:随机数;长度不等
- 处理冲突:
- 开放定址法:线性探测法,二次探测法,随机探测法,冲突了就移动相应位数
- 再散列函数法:冲突了就用另一种方法再散列
- 链地址法:每个地址都是一个单链表,有冲突就放后面(保障有但性能损耗)
- 公共溢出区法:创建一个溢出表,有溢出就放进去(冲突少的情况下)
- 构造哈希表
排序
-
冒泡排序:从下到上,两两比较,每次选出第i位(交换类)
-
简单选择排序:每次选出最小的一个,和第i个交换位置
-
直接插入排序:放好第一个,把后面的一个一个插入
-
希尔排序:间隔k个进行比较交换,k按比例减小(插入排序, O ( n 3 2 ) O(n^\frac{3}{2}) O(n23),不稳定)
-
堆排序:构建大堆顶(从下到上,从右到左,把最大的放根节点),根节点最大,根节点与最后一个节点交换,继续构建大堆顶(选择排序, O ( n l o g n ) O(nlogn) O(nlogn),不稳定,不适合小的序列)
-
归并排序:将子序列两两结合并排序,子序列大小从1开始,不断乘2(时间 O ( n l o g n ) O(nlogn) O(nlogn),递归空间 O ( n + l o g n ) O(n+logn) O(n+logn),非递归空间 O ( n ) O(n) O(n),稳定)
-
快速排序:每次一分为二(两者大小不一定相等),将小的放左边,大的放右边,一直分到不能再分(时间最优 O ( n l o g n ) O(nlogn) O(nlogn),最差 O ( n 2 ) O(n^2) O(n2),空间 O ( l o g n ) O(logn) O(logn),不稳定,交换类)
方法 | 最坏时间 | 空间 | 稳定性 | 适用 |
---|---|---|---|---|
冒泡 | n 2 n^2 n2 | 1 | 稳定 | 基本有序,个数少 |
简单选择 | n 2 n^2 n2 | 1 | 不稳定 | 基本有序,个数少,交换次数少 |
直接插入 | n 2 n^2 n2 | 1 | 稳定 | 基本有序,个数少 |
希尔排序 | n 2 n^2 n2 | 1 | 不稳定 | |
堆排序 | n l o g n nlogn nlogn | 1 | 不稳定 | 内存严格 |
归并排序 | n l o g n nlogn nlogn | n | 稳定 | 需要大量内存,需要稳定 |
快速排序 | n 2 n^2 n2 | logn~n | 不稳定 | 需要大量内存(比归并少),不需要稳定 |