线性结构
1. 核心概念
- 逻辑结构:线性表的核心特征是数据元素之间存在一对一的线性关系。
2. 重点与难点 (Exam Focus)
树与分治
1. 核心概念 (Core Concepts)
- 树的逻辑结构:一对多,层次结构。
- 二叉树 (Binary Tree):最核心结构,区分左右子树。
- 特例:满二叉树、完全二叉树。
- 存储:顺序存储(适合完全二叉树)、链式存储(二叉链表)。
- 操作:二叉树遍历(递归/非递归)、线索化(了解即可)。
- 树与森林 (Tree & Forest)
- 转换:树/森林 二叉树(左孩子右兄弟表示法)。
- 遍历:先根、后根遍历。
- 应用 (Applications)
- 哈夫曼树 (Huffman Tree):最优二叉树,用于数据压缩。
- 二叉排序树 (BST):查找效率 。
- 堆 (Heap):一种特殊的完全二叉树,用于 堆排序。
- AVL 自平衡二叉树
2. 算法思想 (Algorithm Design)
- 分治法 (Divide and Conquer)
- 核心:分解 (Divide) → 解决 (Conquer) → 合并 (Combine)。
- 典型应用:归并排序、大整数乘法、Strassen矩阵乘法。
- 复杂度分析:递归方程求解(代换法、递归树、主方法)。
图与贪心
1. 贪心算法 (Greedy Strategy)
- 核心思想:只看当下,局部最优 整体最优。
- 经典问题:
2. 图论基础 (Graph Theory)
查找与排序
1. 查找 (Search)
- 静态查找:表结构在查找过程中不改变。
- 动态查找:表结构动态调整(如BST,已在树章节复习)。
- 散列技术:
- 哈希表 (Hash Table):通过函数映射实现 查找。
- 关键:哈希函数构造 + 冲突处理。
2. 排序 (Sort)
- 内部排序:数据在内存中。
- 外部排序:数据量大,需借助外存(如归并排序的变种)。
3. 核心考点 (Exam Focus)
- ASL 计算:查找成功与失败的平均查找长度。
- 排序过程模拟:给出一个序列,写出某算法(如快排、希尔)前几趟的结果。
- 算法性能对比:排序算法稳定性 与时间/空间复杂度表格。
考点速查表 (Complexity Table)
| 算法 | 平均时间 | 最坏时间 | 空间 | 稳定性 | 备注 |
|---|---|---|---|---|---|
| 直接插入 | 稳定 | 小或基本有序时快 | |||
| 希尔 | 不稳定 | 增量序列影响大 | |||
| 冒泡 | 稳定 | 可加 flag 优化 | |||
| 快排 | 不稳定 | 综合性能最好 | |||
| 简单选择 | 不稳定 | 移动次数少 | |||
| 堆排序 | 不稳定 | 适合 大,不适合 小 | |||
| 归并 | 稳定 | 需辅助空间 |
动态规划
1. 核心思想 (Core Philosophy)
- 定义:将待求解问题分解成若干个重叠子问题,通过保存子问题的解(备忘录)来避免重复计算。
- 与分治法的区别:
- 基本要素 (必考概念):
2. 经典模型 (Classic Problems)
- 线性模型:
- 区间模型:
- 矩阵连乘问题:寻找最少乘法次数。
- 凸多边形最优三角剖分:与矩阵连乘同构。
- RNA第二结构预测:生物信息学应用。
- 其他应用:
课后习题
第一章 绪论
- 数据结构从逻辑结构(元素之间的关系)分为线性结构和非线性结构(一对多 or 一对一)
- 算法分析是通过分析算法的时间复杂度、空间复杂度,评估其执行效率,从而优化算法性能。
- 时间复杂度的增长速度:指数级 > 多项式级(高次幂 > 低次幂)> 对数级
- 数据元素是构成数据的 基本 单位,数据项是构成数据的 最小 单位。
一、数据为什么需要结构?
核心目的:高效处理数据
- 简化逻辑:通过结构(如数组、树)清晰表达数据间关系,降低理解与操作的复杂度;
- 提升效率:合理结构(如哈希表)优化增删改查的时间/空间性能;
- 节省空间:结构化存储(如链表)避免无结构数据的空间浪费;
- 增强复用:通用结构(如栈、队列)是同类问题的“模板”,减少重复开发。
二、算法与程序的相同点和区别
| 维度 | 相同点 | 区别(算法 vs 程序) |
|---|---|---|
| 核心属性 | 都是解决问题的步骤集合 | 算法是抽象逻辑思路;程序是算法的代码实现 |
| 特性要求 | 依赖清晰逻辑 | 算法必须“有穷、确定、可行”;程序可无限循环(如服务器) |
| 表达载体 | —— | 算法用自然语言/伪代码;程序用编程语言编写 |
| 关注重点 | —— | 算法重“正确性”;程序重“可运行性”(需考虑语法/环境) |
三、用抽象数据类型(ADT)定义矩阵类型
ADT是“数据+操作”的封装,定义矩阵需明确两部分:
-
数据结构:
- 稠密矩阵:用二维数组存储,记录行数
rows、列数cols; - 稀疏矩阵:用三元组(行号、列号、元素值)存储非零元素。
- 稠密矩阵:用二维数组存储,记录行数
-
操作集合(以稠密矩阵为例):
- 初始化:
InitMatrix(&M, rows, cols) - 元素访问:
GetElement(M, i, j)、SetElement(&M, i, j, val) - 矩阵运算:
AddMatrix(M1, M2)(求和)、MultiplyMatrix(M1, M2)(求积)、TransposeMatrix(M)(转置)
- 初始化:
第二章 线性结构
-
装填因子 ():。
- 越大,发生冲突的可能性越大。
-
冲突处理:
- 开放定址法:
- 线性探测: (易产生“堆积”现象)。
- 二次探测:
- 链地址法 (Chaining):冲突元素挂在链表中 (无堆积现象,平均查找长度较短)。
- 开放定址法:
-
排序方法:
- 直接插入:把当前元素插入到前面已排好序的序列中,直到所有元素有序。
- 稳定(相等元素相对位置不变);
- 趟数固定为
n-1,与原序列无关。
- 冒泡:每趟从左到右比较相邻元素,把大的元素 “冒泡” 到右侧(或小的到左侧),直到无交换。
- 趟数由原序列有序程度决定(越有序,趟数越少)。
- 简单选择:每趟找到 “未排序部分的最小元素”,放到已排序部分的末尾。
- 不稳定(如原序列的两个 2,交换后相对位置改变);
- 趟数固定为
n-1,与原序列无关。
- 快速:选一个 “基准元素”,把序列分成 “比基准小” 和 “比基准大” 的两部分(分区),再对两部分递归排序。
- 不稳定(分区时相等元素的相对位置可能被打乱);
- 效率高,但最坏情况(原序列有序)效率低。
- 希尔:按 “增量” 分组,对每组做直接插入排序;逐步减小增量,直到增量为 1(此时就是直接插入排序)。
- 不稳定(分组排序时相等元素会跨组移动);
- 趟数由增量序列决定,与原序列无关。
- 直接插入:把当前元素插入到前面已排好序的序列中,直到所有元素有序。
线性表存储结构:顺序、链式
线性表的链式存储结构主要包括 单链表、循环链表 和 双向链表 三种形式,其中最基本的形式是 单链表。
线性表操作次数:
- 插入操作 (Insertion)
- 插入位置:共 个(含队尾)。
- 最大移动:插在第 1 位,移动 次。
- 最小移动:插在最后,移动 次。
- 平均移动:
- 删除操作 (Deletion)
- 删除位置:共 个。
- 最大移动:删第 1 位,移动 次。
- 最小移动:删最后一位,移动 次。
- 平均移动:
在三对角矩阵中,只有主对角线及其相邻的两条对角线上有非零元素。对于一个 的三对角矩阵 ,其非零元素的分布特征是:当且仅当 时, 是非零元素。
对于元素 ,其跳过的元素个数公式为: (注:如果题目是“行优先”,公式则反过来:)
线性表的 逻辑长度 与 物理长度 总是一致的。
岗哨:在查找之前,将待查找的关键字 存入 。这样做的好处是:在 while 循环中不需要判断下标是否越界,因为最坏情况下一定会在 处找到 。
在索引表中,每个索引项至少包含有 关键字 域和 地址 域这两项。
在采用链地址法解决冲突时,平均查找长度(ASL)主要取决于哈希表的装填因子(Load Factor),计算公式如下:
- 装填因子 : (其中 是数据个数, 是哈希表长度)。
- 平均查找长度(成功):
- 平均查找长度(不成功): (或者简单近似为 )
若不考虑基数排序,则在排序过程中,主要进行的两种基本操作是关键字的比较和数据的排序
哈希表(Hash Table,也称散列表)是一种通过建立键(Key)与存储地址(Address)之间直接映射关系来实现高效查找的数据结构。
- 访问速度快
- 数据无序
- 冲突必然性
- 存储空间与时间的平衡
第三章 递归与分治
汉诺塔问题:
- 移动 个盘子的总步数 的递推公式为:
- 通项公式计算:
分形是基于自然界图形的 自相似 特点
- Koch 曲线、康托尔集、曼德博集合
递归算法的计算过程是从大到小,而迭代算法的计算过程是从小到大
系统用于保存递归函数调用信息的堆栈叫调用栈
针对分治问题(Divide and Conquer)的复杂度计算,最核心且常用的方法有以下三种
- 主定理
- 递归树
- 代入法
可以使用分治策略的问题通常需要满足以下四个特征:
- 可分性:原问题可以分解为若干个规模较小的相同子问题。
- 子问题独立性:各个子问题之间相互独立,即子问题之间不包含公共的子子问题(这是分治与动态规划的主要区别)。
- 递归出口:子问题规模足够小时可以很容易地直接求解。
- 合并性:利用子问题的解可以合并出原问题的解。
树
在任何一棵二叉树中,叶子结点(度为 0 的结点)与度为 2 的结点之间存在如下关系:- :叶子结点的个数(度为 0)
- :度为 2 的结点个数
完全二叉树:除了最后一层外,其他各层都是满的,且最后一层的结点都集中在左侧。
哈夫曼树是通过不断“合并”节点构建出来的:
- 初始状态:我们有 个叶子结点,它们各自都是一棵独立的树(此时有 个连通分量)。
- 合并规则:每次从所有树中选出根结点权值最小的两棵,合并成一棵新树。
- 关键动作:每次合并,都会消耗掉 2 个旧的根结点,并生成 1 个新的分支结点(作为这两个结点的父结点)。
- 终止状态:直到最后只剩下一棵树为止。
树转换为二叉树(孩子-兄弟表示法):
- 将所有孩子连起来
- 断开除最左孩子外,其他孩子与父节点的连线
- 将其他孩子移为最左孩子的右子树
在数据结构中,堆通常是指完全二叉树。它分为两种:
- 大根堆:任何一个父结点的值都大于或等于它的左、右孩子结点。
- 小根堆:任何一个父结点的值都小于或等于它的左、右孩子结点。 从序列上看,如果一个序列是堆,必须满足:
- 它的左孩子是第 个元素。
- 它的右孩子是第 个元素。
- 必须满足: 且 (大根堆)
2-3 树是一种非常特殊的自平衡搜索树。你可以把它看作是普通二叉搜索树的“升级版”。它的名字“2-3”来源于它节点的分叉(孩子)数量。
哈夫曼树 WPL 的计算有两种方法:
- 方法 A(定义法): 。
- 方法 B(求和法,更简单): 所有非叶子结点的权值之和。
二叉树的先序遍历、中序遍历和后序遍历的共同特征是 遍历左子树先于右子树
在结点数为 的红黑树中,插入、删除、查找结点的复杂度分别为:、、。
图
-
最大边数但仍可能不连通: 若无向图有 个顶点,能构成的最大非连通图的边数是:
(即 个点全连接,1 个点孤立)
-
保证连通的最小边数: 若要 个顶点的无向图一定连通,所需的最小边数是: