数据结构与算法
学习时间:2021年9月16日21:40:03
作者:聪头
参考:王道考研2022–数据结构篇
1.绪论
数据
- n个数据对象
- n个数据元素
- n个数据项
- n个数据元素
算法5个重要特性
- 有穷性
- 确定性
- 可行性
- 输入
- 输出
2.线性表
2.1 顺序表
1 |
|
2.2 链表
1 |
|
2.3 双链表
- 有两个指针prior和next,分别指向前驱和后继
1 |
|
3.栈和队列
3.1 顺序栈
1 |
|
3.2 链式栈
1 |
|
3.3 顺序队列
1 |
|
3.4 链式队列
1 |
|
补充:第三章main函数
1 |
|
实战:栈实现括号匹配
1 | ///应用 |
实战:表达式求值(C#)
1 | ///使用栈实现括号匹配的检查 |
main函数
1 | static void Main(string[] args) |
4.串
- 通用代码
1 | //串,均从下标为1开始 |
4.1 朴素模式匹配
1 | //朴素模式匹配 |
4.2 KMP算法
1 | //KMP算法 |
补充:第四章main函数
1 | int main() |
5.树
5.1 二叉树的遍历
二叉树数据结构
- 适用于线索二叉树
1 |
|
遍历代码
1 | //前序遍历 |
补充:5.1节main函数
1 | //ABD0G00E00CF000 |
5.2 线索二叉树(以中序为例)
1 | //中序线索化 |
补充:5.2节main函数
1 | //生成中序线索二叉树 |
5.3 平衡二叉树
参考b站URL:https://www.bilibili.com/video/BV1NV411E7DQ?from=search&seid=4549868522115408456
AVL数据结构
1 |
|
代码实现
1 | //获得高度 |
补充:5.3节main函数
1 | int n, num; |
5.4 树、森林与二叉树转换
树 -> 二叉树规则:左孩子,右兄弟
森林 -> 二叉树规则:每棵树采用“左孩子,右兄弟”规则转化为二叉树(此时树根必无右孩子),再将各棵树之间看作兄弟,使用同样规则相连。
二叉树 -> 树/森林:根据“左孩子,右兄弟”还原即可
6.图
- 邻接矩阵(顶点和边下标均从0开始)
1 | //图 默写 |
6.1 图的遍历
邻接矩阵初始化和通用操作
- 参考王道2022 P206 图6.5(b)
1 | //邻接矩阵初始化 |
图的访问操作
1 | bool visited[MAX_VERTEX_NUM] = { false }; //全局visited |
深度优先搜索 DFS
1 | //1.DFS遍历 |
广度优先搜索 BFS
1 | //BFS遍历 |
6.2 最小生成树 MST
邻接矩阵初始化
- 参考王道2022 P227 图6.15
1 | //邻接矩阵初始化 |
Prim算法 O(V^2^) 边稠密
1 | ///Prim O(n^2) = O(n-1) * O(2n) |
Kruskal算法 O(ElogE) 边稀疏
- 需要使用并查集
1 | ///Kruskal 堆排序:O(E|logE|) |
6.3 最短路径
Dijkstra算法 单源 O(V^2^)
- 时间复杂度:O(V^2^)
- 不允许带有负权值的边
- 解决单源最短路问题
- 邻接矩阵
1 | //邻接矩阵初始化 |
- 核心代码(完整)
1 | //迪杰斯特拉算法(单源最短路问题) |
Floyd算法 多源 O(V^3^)
- 时间复杂度:O(V^3^)
- 允许图中带有负权值的边,但不允许有包含带负权值的边组成的回路
- 解决多源最短路问题
- 参考王道2022视频2.6.11 13:00
1 | //邻接矩阵初始化 |
- 核心代码(完整)
1 | //弗洛伊德算法(多源最短路径) |
6.4 拓扑排序
1 | //邻接矩阵初始化 |
补充:第六章main函数
1 | int main() |
7.查找
7.1 顺序查找
1 | //顺序查找 |
7.2 折半查找
1 | //折半查找 |
8.排序
- 所有数组元素均从下标1处开始
- 所有排序默认升序排序
- 部分通用代码
1 |
|
—– 插入排序 —–
8.1 直接插入排序 O(n^2^)
平均时间复杂度:O(n^2^)
稳定性:稳定
适用性:顺序表和链表
思路:选择无序列表中的第一个元素,插入到有序列表中
1 | void InsertSort(ElemType arr[], int length) |
改进:折半插入排序
平均时间复杂度:同上
稳定性:稳定
适用性:顺序表
思路:同上,只是每次在有序列表选择插入位置时使用折半查找
1 | void InsertSort_Binary(ElemType arr[], int length) |
8.2 希尔排序
平均时间复杂度:可能约O(n^1.3^),略优于O(n^2^);当d=1时退化为直接插入排序
稳定性:不稳定
适用性:顺序表
思路:选取不断缩小的增量,使列表从部分有序到整体有序
1 | void ShellShort(ElemType arr[], int length) |
—– 交换排序 —–
8.3 冒泡排序 O(n^2^)
平均时间复杂度:O(n^2^)
稳定性:稳定
思路:每次选择一个最小(大)的元素,通过逐个交换到列表一端
1 | void BubbleSort(ElemType arr[], int length) |
8.4 快速排序 O(nlogn)
平均时间复杂度:O(nlogn)
稳定性:不稳定
思路:每次选取一个值为枢轴,递归调用,左小右大,确定其位置
1 | void QuickSortCore(ElemType arr[], int low, int high); |
—– 选择排序 —–
8.5 简单选择排序 O(n^2^)
平均时间复杂度:O(n^2^)
稳定性:不稳定
思路:每次选择无序列表中最小的并入有序列表
1 | void SelectSort(ElemType arr[], int length) |
8.6 堆排序 O(nlogn)
平均时间复杂度:O(n^2^)
分析:建堆O(n),排序需要 n - 1 次向下调整的操作,为O(nlogn)。共O(n) + O(nlogn) ~ O(nlogn)
稳定性:不稳定
思路:
- 建堆,从非叶结点往前,确保根 >=(或<=) 左、右
- 排序,每次排序交换头尾两个元素,再调整堆
1 | void MaxHeapSort(ElemType arr[], int length); //堆排序 |
—– 特殊排序 —–
8.7 归并排序 O(nlogn)
平均时间复杂度:O(nlogn)
分析:分析:每趟归并的时间复杂度为O(n),共需logn(向上取整)趟归并,故为O(nlogn)
空间复杂度:O(n)
稳定性:稳定
思路:递归,分别对左右归并排序
1 | void MergeSort(ElemType arr[], int length); //归并排序入口 |