数据结构
大二上学期数据结构的复习笔记,目前已完结。
一、绪论
1. 基本概念
- 数据:程序能处理的符号的总称
- 数据元素:数据的基本单位,由数据项组成(有独立含义的最小单位)
- 数据结构:有相互关系的数据元素的集合,三元素:逻辑结构、运算、存储结构(物理结构,元素及关系的存储表示,顺序/链式/索引/散列),表现为逻辑抽象模型(抽象数据类型)和具体实现
- 数据类型:性质相同的值的集合和集合上定义的操作的总称
- 抽象数据类型 ADT:数据元素的集合(数据对象)、关系集合、操作集合
- 算法:解决方案的准确完整描述,有穷/确定/可行/输入/输出,正确/可读/健壮/高效,设计取决于逻辑结构,实现依赖于存储结构
- 程序:数据结构+算法,基于编程语言的算法实现
2. 渐进分析
- 渐进上界/紧界/下界:$O/\Theta/\Omega$,记作 $T\le/=/\ge g$,$\forall n\ge n_0,c_1g(n)\le f(n)\le c_2g(n)$,$O$ 与 $\Theta$ 常混用
- 时间复杂度是空间复杂度的上界
- 主定理:$T(n)=aT(n/b)+f(n)$,$a\ge 1,b>1$
- 若 $f(n)=O(n^{\log_b a-\epsilon})$,则 $T(n)=\Theta(n^{\log_b a})$
- 若 $f(n)=\Theta(n^{\log_b a}\log^k n)$,则 $T(n)=\Theta(n^{\log_b a}\log^{k+1} n)$
- 若 $f(n)=\Omega(n^{\log_b a+\epsilon})$,且 $af(n/b)\le cf(n)$,则 $T(n)=\Theta(f(n))$
3. 常见算法
- 斐波那契数列
1 | |
二、线性表
1. 基本概念
- 线性表(序列):数据元素的有限序列
- 向量(顺序表):线性表基于数组的存储表示
- 列表(链表):线性表基于链式存储的表示
- 串:字符组成的有限序列,空串/空白串
- 排序码:排序依据
2. 向量
- 随机打乱
1 | |
- 二分查找
1 | |
- 归并排序(可用于统计逆序对)
1 | |
- 快速排序(可用于 K-选取,$O(n)$ 平均复杂度)
1 | |
- 排序算法比较
| 方法 | 平均情况 | 最好情况 | 最差情况 | 辅助空间 | 稳定性 |
|---|---|---|---|---|---|
| 冒泡 | $O(n^2)$ | $O(n)$ | $O(n^2)$ | $O(1)$ | 稳定 |
| 选择 | $O(n^2)$ | $O(n^2)$ | $O(n^2)$ | $O(1)$ | 不稳定 |
| 插入 | $O(n^2)$ | $O(n)$ | $O(n^2)$ | $O(1)$ | 稳定 |
| 希尔 | $O(n\log^2 n)$ | $O(n^{1.3})$ | $O(n^2)$ | $O(1)$ | 不稳定 |
| 堆 | $O(n\log n)$ | $O(n\log n)$ | $O(n\log n)$ | $O(1)$ | 不稳定 |
| 归并 | $O(n\log n)$ | $O(n\log n)$ | $O(n\log n)$ | $O(n)$ | 稳定 |
| 快速 | $O(n\log n)$ | $O(n\log n)$ | $O(n^2)$ | $O(\log n)$ | 不稳定 |
3. 列表
- 归并排序:原地归并
- 排序算法比较:选择排序稳定
4. 串
- 蛮力匹配
1 | |
- KMP next
1 | |
- KMP nextval
1 | |
三、栈与队列
1. 表达式求值
- 中缀转后缀:数字直接过,左括号入栈,右括号弹栈至左括号,运算符弹栈至栈顶优先级小于自身
- 后缀求值:数字入栈,遇运算符弹栈两元素,结果入栈
- 优先级:阶乘 $>$ 指数
2. 栈混洗
- $n$ 元素:卡特兰数 $h(n)=\frac{C^{n}_{2n}}{n+1}$
- 递推:$h(n)=h(n-1)h(0)+h(n-2)h(1)+\cdots+h(0)h(n-1)$
- 判断可行混洗序列
1 | |
3. 单调栈
- 求每个元素右侧第一个比它大的元素下标
1 | |
4. 二项式展开系数
1 | |
四、树
1. 基本概念
- 深度:从根到节点的路径长度(根节点为 $0$)
- 高度:到叶子节点的最长路径长度
- 树高:根节点高度(单节点为 $0$,空树为 $-1$)
- 完全二叉树:除最后一层全满,最后一层往左靠
2. 二叉树
- 节点数:$n_0=n_2+1$
- 顺序表示:从 $0$ 开始
- 形态数:卡特兰数(前序固定,中序可能情况)
- 重构:前/后+中可重构,前+后不可重构(真二叉树可)
3. 堆
- 插入:末尾插入,和父节点比较交换(上滤)
- 删除:根和末尾交换,和子节点比较交换(下滤)
- 构建:从最右的非叶节点逐个下滤,$O(n)$
- 用堆实现 $\mathrm{Huffman}$ 树
五、搜索树
1. 二叉搜索树
- 二叉树是二叉搜索树当且仅当中序遍历非降
- 节点删除:叶节点直接删;单子节点提升子节点;双子节点用中序前驱/后继替换
- 按排列的平均高度 $O(\log n)$,按形态的平均高度 $O(\sqrt{n})$
- 理想平衡二叉搜索树:树高 $O(\log n)$,完全/满二叉搜索树
- 一维范围查询:找 $\mathrm{LCA}$,左路程对左转过程遍历输出右子树,右路程对右转过程遍历输出左子树
2. AVL
- 右旋 $\mathrm{zig}$,左旋 $\mathrm{zag}$
- 插入:从插入点回溯,首个不平衡记为 $g$,沿回溯路径取 $p$,$v$(更高的孩子)
- 删除:从删除点的父节点开始,迭代调整
3. B-Tree
- 根节点是第 $0$ 层,高度为 $1$,下分支为第 $0$ 层分支,分支数 $[2,m]$;非根节点 $[\lceil m/2\rceil,m]$
- $m$ 阶 B-Tree $\Rightarrow$ $(\lceil m/2\rceil,m)$ 树
- 分支数 $L_{k-1}+N_k=L_k$,$N_k$ 为第 $k$ 层关键码总数,可递推
- $\log_m(N+1)\le h\le \log_{\lceil m/2\rceil}(\frac{N+1}{2})+1\Rightarrow h=O(\log_m N)$
- 插入:上溢分裂,迭代进行
- 删除:叶节点直接删,非叶节点用中序前驱/后继替代,下溢(借父,父借兄弟或合并)
4. 红黑树
- 任何动态操作(插入删除)引起的结构变化量不超过 $O(1)$
- 根和外部节点为黑;红节点的父和子为黑;根到任一外部节点经过的黑节点数目一样
- 推论:根到外部节点路径黑节点不少于红节点
- 黑深度:除根外经过的黑节点(包括外部节点)
- 黑高度:从该节点到外部节点经过的黑节点(不包括外部节点);树黑高度为根黑高度
- 红黑树等价于 $(2,4)$ 树,节点对应关键码
- 红黑树高度 $\log_2(n+1)\le h\le 2\log_2(n+1)$
- 插入:染红,双红修正(父 $p$,祖父 $g$,叔父 $u$)
- $u$ 黑:$\mathrm{zigzag}$
- $u$ 红:染黑 $p,u$,染红 $g$,递归修正 $g$
- 删除:双黑修正
5. KD-Tree
- 建树:找中位点,递归划分 $(O(n\log n))$
- 范围查询:区域和节点对应分割线不相交则剪枝,否则切割区域后进入两侧,再访问自身
- 最近邻查询:访问自身后进入一侧,另一侧依垂直距离判断
六、图
1. 基本概念
- 简单路径:路径上顶点不重复
- 连通分量:非连通图的极大连通子图
- 强连通分量:$\mathrm{Tarjan}$ 有向环缩点法
2. 遍历
- 深度优先搜索:发现次序先序(dTime),访问次序后序(fTime)
- 边的类型:树边、前向边、后向边、跨边
1 | |
3. 图论算法
- 优先级搜索
1 | |
- $\mathrm{Bellman-Ford}$
- $\mathrm{Floyd}$
- 拓扑排序
七、散列
- $\mathrm{hash}=f(\mathrm{key})$,$\mathrm{key}$ 为关键码,$f$ 为散列函数,直接定址/除余/MAD/数字分析/平方取中/折叠/随机
- 冲突处理:多槽位/独立链/公共溢出区
- 开放定址/闭散列策略:动态删除+线性/平方/双向平方(表长 $M% 4=3$ 前 $M$ 次可遍历)/随机试探+再散列(扩容)
- 散列码转换:强制转换/分块求和/字符串多项式
数据结构
https://sqzr2319.github.io/25Fall/DSA/