一篇围绕算法分析的数学基础与渐进复杂度展开的学习笔记。
算法分析需要两套前置知识:用于推导求和、比较增长率的数学工具,以及用于量化资源消耗的渐进记号体系。本篇先整理前者(指数、对数、级数、模运算、证明方法),再展开后者(
1. 数学基础
1.1 指数
1.2 对数
在计算机科学中,若无特别声明,所有对数均以 2 为底。
定义:
定理 1.1(换底公式):对任意
定理 1.2:
常用等式:
| 公式 | 说明 |
|---|---|
| 对所有 | |
1.3 级数
几何级数:
当
常用算术级数:
调和级数:
其中
级数运算常用恒等式:
1.4 模运算
若
| 性质 | 示例 |
|---|---|
| 若 | |
| 若 |
1.5 证明方法
算法分析中最常使用的三种证明方法:
| 方法 | 思路 | 结构 |
|---|---|---|
| 归纳法 | 证明最小情形(基准)成立,再假设 | 基准情形 → 归纳假设 → 归纳步骤 |
| 反证法 | 假设结论为假,推导出矛盾 | 假设 ¬P → 推导 → 矛盾 → 故 P 成立 |
| 反例法 | 举出一个不满足结论的具体实例 | 直接给出反例即可推翻命题 |
归纳法示例——证明斐波那契数
- 基准:
, - 归纳:假设对
成立,则
2. 复杂度分析
2.1 渐进记号
评估算法资源消耗时,比较的是函数的相对增长率(relative rate of growth),而非具体数值。渐进记号体系提供了一套正式框架。
定义:设
| 记号 | 读法 | 定义 | 含义 |
|---|---|---|---|
| 大 O | 存在 | ||
| Omega | 存在 | ||
| Theta | |||
| 小 o |
注意:
是错误的写法——不等式已隐含在 的定义中。同时,不要在 中保留常数和低阶项: 和 都应写为
2.2 增长率比较
极限比较法:对于两个函数
| 极限值 | 结论 |
|---|---|
| 有限非零常数 | |
查表法:
| 函数 | 名称 | 典型场景 |
|---|---|---|
| 常数 | 简单语句 | |
| 对数 | 二分查找 | |
| 对数的平方 | ||
| 平方根 | ||
| 线性 | 顺序扫描 | |
| 线性对数 | 归并排序、堆排序 | |
| 平方 | 冒泡排序、选择排序 | |
| 立方 | 矩阵乘法(朴素) | |
| 指数 | 穷举搜索 |
增长率由慢到快:
值得注意的是:
2.3 运算法则
法则 1:若
法则 2:若
法则 3:对任意常数
推论——复杂度分析中的简化原则:
| 原则 | 说明 |
|---|---|
| 忽略常数因子 | |
| 忽略低阶项 | |
| 加法取最大 | 循环并列时复杂度取各段最大者 |
| 乘法取乘积 | 嵌套循环时复杂度取各层乘积 |
2.4 运行时间计算
分析运行时间的基本方法:逐语句累加运行时间,忽略常数,关注最内层循环的迭代次数。
a. 单层循环
int sum(int n) {
int total = 0; // O(1)
for (int i = 0; i < n; i++) // n 次迭代
total += i; // O(1) 每轮
return total; // O(1)
}总时间:
b. 嵌套循环
for (int i = 0; i < n; i++) // n 次
for (int j = 0; j < n; j++) // n 次/每轮
count++; // O(1)总时间:
c. 依赖外层的循环
for (int i = 0; i < n; i++) // n 次
for (int j = 0; j < i; j++) // i 次/每轮
count++;d. 对数时间
while (n > 1) {
n /= 2; // 每轮将 n 减半
/* O(1) 操作 */
}循环次数为
e. 递归函数
递归函数的时间复杂度通过递推关系式描述,判断复杂度的关键在于确定
- 递归层数
- 第
层子任务数 - 每层每个子任务的规模
(往往并非常数,与层级有关)
则总复杂度可以表示如下:
也就是将每层的总规模计算后,逐层累加。
情形 1:
递归深度为
情形 2:
每个问题分为两个子问题,第
情形 3:
递归深度为
情形 4:
递归深度为
| 递推式 | 含义 | 复杂度 | 典型算法 |
|---|---|---|---|
| 逐次减一 + 常数时间 | 线性递归(如阶乘) | ||
| 指数分支 + 常数时间 | 斐波那契朴素递归 | ||
| 减半 + 常数时间 | 二分查找 | ||
| 两分 + 线性时间合并 | 归并排序 |
小结
| 主题 | 核心内容 |
|---|---|
| 数学基础 | 指数恒等式、对数换底公式、几何/算术/调和级数、模运算同余性质、归纳法与反证法 |
| 渐进记号 | |
| 运算法则 | 加法取最大、乘法取乘积、忽略常数和低阶项、多项式取最高次 |
| 运行时间计算 | 逐句累加 → 关注最内层循环 → 查级数公式求和 → 递归问题检查每层工作量与分支数 |