相关笔记: 3.1 算法 | 3.2 函数的增长

概览

本节介绍了算法复杂度分析的基本方法,以时间复杂度(time complexity)为核心,系统分析了搜索算法、排序算法和矩阵乘法的效率。讨论了最坏情况(worst-case)最好情况(best-case)平均情况(average-case)三种分析视角,并引入了可解性(solvable)可 tractable(tractable)不可解(unsolvable)等计算复杂性理论的基本概念。

  • 时间复杂度用算法执行的基本操作次数来度量,而非实际运行时间
  • 线性搜索最坏情况 二分搜索最坏情况
  • 冒泡排序插入排序最坏情况均为
  • 最有效的排序算法(如归并排序)可达
  • 矩阵乘法的朴素算法复杂度为
  • 可解问题有算法能解决;易解问题有多项式时间算法;不可解问题(如停机问题)无任何算法能解决

一、知识结构总览

graph TB
    A["3.3 算法复杂度分析 Complexity of Algorithms"] --> B["时间复杂度 Time Complexity"]
    A --> C["搜索算法分析"]
    A --> D["排序算法分析"]
    A --> E["矩阵乘法复杂度"]
    A --> F["算法范式"]
    A --> G["复杂度的实际意义"]

    B --> B1["基本操作计数"]
    B --> B2["最坏情况分析"]
    B --> B3["平均情况分析"]
    B --> B4["最好情况分析"]

    C --> C1["线性搜索 Θ(n)"]
    C --> C2["二分搜索 Θ(log n)"]
    C --> C3["线性搜索平均情况"]

    D --> D1["冒泡排序 Θ(n²)"]
    D --> D2["插入排序 Θ(n²)"]
    D --> D3["归并排序 O(n log n)"]

    E --> E1["朴素矩阵乘法 O(n³)"]
    E --> E2["布尔矩阵乘积 O(n³)"]
    E --> E3["矩阵链乘法优化"]

    F --> F1["蛮力算法 Brute Force"]
    F --> F2["贪心算法 Greedy"]
    F --> F3["分治算法 Divide-and-Conquer"]

    G --> G1["复杂度术语表"]
    G --> G2["可解 vs 不可解"]
    G --> G3["P vs NP"]
    G --> G4["实际运行时间对比"]

二、核心思想

核心思想

本节的核心思想是算法复杂度分析:通过计算算法在输入规模为 时所需的基本操作次数,而非依赖特定硬件的实际运行时间,来度量算法的效率。复杂度分析使我们能够在最坏情况平均情况最好情况三种视角下评估算法性能,并据此选择适合问题规模和约束的算法。结合大O、大、大 等渐近记号,复杂度分析为算法的比较和选择提供了统一的理论框架。

1. 时间复杂度的基本概念

时间复杂度(Time Complexity)

算法的时间复杂度用算法在输入规模为 时所使用的基本操作次数来度量。

  • 基本操作可以是:整数比较、加法、乘法、除法等
  • 使用操作次数而非实际时间的原因:
    • 不同计算机执行同一操作的时间不同(超级计算机 vs 个人电脑可能差 1000 倍)
    • 不同操作(加法 vs 乘法)的执行时间也不同
  • 空间复杂度(space complexity):算法所需的计算机内存量(本节不深入讨论)

三种分析视角

类型定义用途
最坏情况(worst-case)对给定规模 的所有输入,算法所需的最大操作数保证算法一定能完成
平均情况(average-case)对给定规模 的所有可能输入,算法所需的平均操作数评估算法的典型性能
最好情况(best-case)对给定规模 的所有输入,算法所需的最小操作数了解算法的最优表现

2. 搜索算法的复杂度分析

求最大值算法的复杂度

个元素中找最大值(Algorithm 1 of Section 3.1):

  • 对第 2 到第 个元素,每次需要 2 次比较(
  • 最后一次循环退出需要 1 次比较
  • 总计: 次比较
  • 时间复杂度:(与具体输入无关)

线性搜索(Linear Search)的复杂度

个元素的列表中搜索元素 (Algorithm 2 of Section 3.1):

  • ,需要 次比较
  • 最坏情况 不在列表中): 次比较
  • 平均情况 在列表中且等概率出现在任何位置):

故平均情况也是

二分搜索(Binary Search)的复杂度

个有序元素的列表中搜索 (Algorithm 3 of Section 3.1):

  • 每次迭代将搜索范围减半,使用 2 次比较
  • 个元素
  • 总比较次数:
  • 最坏情况复杂度(更精确地,
  • 二分搜索比线性搜索高效得多:

3. 排序算法的复杂度分析

冒泡排序(Bubble Sort)的复杂度

冒泡排序通过多趟扫描,每趟将相邻元素中较大的向后交换:

  • 第 1 趟: 次比较
  • 第 2 趟: 次比较
  • 趟: 次比较
  • 总比较次数:

  • 冒泡排序始终使用这么多比较(即使列表已有序),最坏情况复杂度:

插入排序(Insertion Sort)的复杂度

插入排序在第 步将第 个元素插入到前 个已排序元素的正确位置:

  • 最坏情况(第 个元素需要与前面所有 个元素比较): 次比较
  • 总比较次数:

  • 最坏情况复杂度
  • 最好情况(列表已有序):每步只需 1 次比较,总计
  • 插入排序在”几乎有序”的列表上表现很好

高效排序算法

最有效的排序算法可以在 时间内排序 个元素,例如:

  • 归并排序(Merge Sort):使用分治策略,将在第 8 章和第 11 章详细介绍
  • 快速排序(Quick Sort):平均 ,最坏
  • 是基于比较的排序算法的理论下界

4. 矩阵乘法的复杂度

朴素矩阵乘法(Algorithm 1)

计算 矩阵 矩阵 的乘积:

  • 乘积有 个元素
  • 每个元素需要 次乘法和 次加法
  • 对于两个 矩阵: 次乘法和 次加法
  • 总复杂度:

布尔矩阵乘积(Algorithm 2)

两个 的 0-1 矩阵的布尔积:

  • 每个元素需要 次 AND 和 次 OR
  • 每个元素共 次位运算
  • 总计: 次位运算

矩阵链乘法的优化

矩阵乘法满足结合律,不同的乘法顺序影响总乘法次数:

  • )、)、
  • 方案一
  • 方案二
  • 方案二节省了 22000 次乘法!

5. 算法范式与蛮力算法

蛮力算法(Brute Force)

蛮力算法是最直接的算法设计方法,基于问题的陈述和定义来解决问题,不考虑计算资源的限制。

  • 特点:检查所有可能的解,寻找最优
  • 优点:简单直接,对小规模输入实用
  • 缺点:对大规模输入效率极低
  • 例子:
    • 求最大值:逐一比较所有元素
    • 朴素字符串匹配:逐一检查所有位置
    • 最近点对:计算所有点对的距离(),而最优算法可达

6. 复杂度的实际意义

复杂度术语表

复杂度术语典型算法
常数复杂度取列表前 100 个元素的最大值
对数复杂度二分搜索
线性复杂度线性搜索
线性对数复杂度归并排序
多项式复杂度冒泡排序(
, 指数复杂度可满足性问题的穷举搜索
阶乘复杂度旅行商问题的穷举

可解性分类

  • 可解问题(solvable):存在算法能解决
  • 不可解问题(unsolvable):不存在任何算法能解决(如停机问题,由 Alan Turing 证明)
  • 易解问题(tractable):存在多项式时间算法能解决(属于类 P
  • 难解问题(intractable):不存在多项式时间算法(或尚未发现)
  • NP 问题:解可以在多项式时间内验证
  • NP 完全问题(NP-complete):NP 中”最难”的问题,若任一 NP 完全问题有多项式时间算法,则所有 NP 问题都有

P vs NP

P vs NP 问题是计算机科学最著名的未解问题之一,也是千禧年七大数学难题之一(奖金 100 万美元)。

  • P:可以在多项式时间内求解的问题类
  • NP:可以在多项式时间内验证解的问题类
  • 显然 ,但 是否成立尚无定论
  • 大多数理论计算机科学家相信
  • Cook-Levin 定理(1970s):可满足性问题(SAT)是第一个被证明为 NP 完全的问题

三、补充理解与易混淆点

补充理解

补充1:为什么平均情况分析往往困难

平均情况分析需要对输入的概率分布做出明确假设,而实际输入分布往往未知或难以精确建模(Knuth, 1997)。例如,快速排序的平均复杂度 建立在”所有排列等概率”的假设之上,但实际数据可能呈现特定的偏序模式,导致性能偏离理论预期(Sedgewick, 1998)。

为应对这一困难,算法设计领域发展了多种替代分析方法。随机化算法(randomized algorithms)通过在算法执行过程中引入随机选择,使得即使面对恶意构造的最坏输入,期望运行时间也能得到保证——随机化快速排序就是典型例子(Motwani & Raghavan, 1995)。摊还分析(amortized analysis)则从另一角度出发:不要求单次操作的最坏情况,而是证明一系列 次操作的总代价的上界,从而得到每次操作的”平均”代价——动态数组的扩容策略是经典应用案例(Tarjan, 1985)。这两种方法都避免了传统平均情况分析对输入分布的依赖,使分析结果更具鲁棒性。

  • Algorithm Visualizer — 算法可视化,可对比不同输入下的运行时间
  • Oakland Algorithm Visualizations — 排序算法性能对比 来源:Knuth, D. E. (1997). The Art of Computer Programming, Vol. 3: Sorting and Searching (2nd ed.), Addison-Wesley, Section 5.2.2. 来源:Cormen, T. H., et al. (2009). Introduction to Algorithms (3rd ed.), MIT Press, Chapter 12.

补充2:实际编程中的性能优化策略

理解算法复杂度是性能优化的基础,但实际工程中的优化遵循明确的优先级层次:算法选择 > 数据结构选择 > 常数级优化 > 微优化(Aho et al., 1986)。选择正确的算法可以将运行时间从数天缩短到数秒,而底层微优化通常只能带来常数倍的提升。

在算法与数据结构之上,缓存友好性(cache friendliness)是现代计算环境中不可忽视的因素。分块矩阵乘法(cache-oblivious algorithm, Frigo et al., 1999)通过递归分块使数据访问模式适应 CPU 缓存层次,可比朴素的逐元素实现快 4-8 倍。此外,实际工程中需要在时间、空间和代码可维护性之间做出权衡——正如 Knuth(1974)的名言:“过早优化是万恶之源”(“We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil”)。正确的做法是先用清晰的代码实现正确算法,再通过 profiling 工具(如 Python 的 cProfile、C++ 的 perf、Java 的 VisualVM)定位实际瓶颈,针对热点进行有依据的优化。

  • DSA Visualizer — 交互式算法性能分析
  • Big O Notation Tutorial — 复杂度分析实用指南 来源:Aho, A. V., Hopcroft, J. E. & Ullman, J. D. (1974). The Design and Analysis of Computer Algorithms. Addison-Wesley. 来源:Knuth, D. E. (1968). The Art of Computer Programming, Vol. 1: Fundamental Algorithms. Addison-Wesley, Section 1.3.

易混淆点

误区:时间复杂度与空间复杂度

  • ❌ 混淆时间复杂度和空间复杂度,认为 的算法在所有方面都是
  • ✅ 时间复杂度和空间复杂度是两个独立的度量维度:
    • 时间复杂度:算法执行所需的操作次数(或时间)
    • 空间复杂度:算法执行所需的内存空间
  • 一个算法可能时间复杂度优秀但空间复杂度差,反之亦然
  • 例如:归并排序时间 但需要 额外空间;原地排序(如堆排序)空间 但实现更复杂
  • 时空权衡(time-space tradeoff)是算法设计中的常见主题

误区:最坏情况与平均情况的区别

  • ❌ 认为最坏情况就是”通常情况”,或认为平均情况一定比最坏情况好很多
  • ✅ 两者的区别:
    • 最坏情况:对所有输入的上界保证,无论输入如何,算法的操作数不会超过此值
    • 平均情况:对所有输入的期望值,需要概率分布假设
  • 有时两者相同:冒泡排序的最坏情况和平均情况都是
  • 有时差距巨大:快速排序最坏 ,平均
  • ⚠️ 平均情况依赖概率假设,若假设不成立,实际表现可能与分析不符
  • 在安全关键系统(如医疗、航空)中,必须使用最坏情况分析

四、习题精选

习题概览

题号范围核心考点难度
1-4给定代码段的大O估计
5-6求最小自然数算法的比较次数⭐⭐
7线性搜索 vs 二分搜索的实际选择
8快速幂算法的乘法次数⭐⭐
9-10位串中 1 的计数算法⭐⭐
11-12暴力算法的大O估计⭐⭐
13-14多项式求值(常规法 vs Horner 法)⭐⭐
15-17给定时间内可解决的最大 ⭐⭐
18-19给定 的实际运行时间计算
20-21输入规模加倍时的时间变化⭐⭐
22-23最好情况与平均情况分析⭐⭐⭐
24最优算法的概念⭐⭐
25-31各种搜索算法的复杂度分析⭐⭐⭐
32-34排序与字符串算法的复杂度⭐⭐⭐
35-37二分插入排序与字符串匹配⭐⭐⭐
38-40暴力算法的复杂度估计⭐⭐
41-42调度问题的复杂度⭐⭐⭐
43-44搜索/排序算法输入加倍时的比较次数变化⭐⭐
45-49矩阵乘法优化(上三角矩阵、矩阵链乘法)⭐⭐⭐

题1:线性搜索的复杂度分析

题目

分析线性搜索算法在 个元素的列表中搜索元素 的时间复杂度: (1)最坏情况下需要多少次比较? (2)若 在列表中且等概率出现在任何位置,平均需要多少次比较?

题2:嵌套循环的时间复杂度分析

题目

分析以下代码片段的时间复杂度:

for i from 1 to n:
    for j from 1 to n:
        print(i + j)

题3:二分搜索的三种情况复杂度

题目

分析二分搜索算法在 个有序元素的列表中搜索元素 的: (1)最好情况时间复杂度 (2)最坏情况时间复杂度 (3)平均情况时间复杂度

题4:用主定理分析归并排序递推关系

题目

分析以下递归算法的时间复杂度: 这是归并排序的递推关系。请用主定理(Master Theorem)求解。

题5:Strassen 矩阵乘法的复杂度分析

题目

分析 Strassen 矩阵乘法的时间复杂度: (1)用主定理证明其时间复杂度为 。 (2)将 Strassen 算法与朴素矩阵乘法 进行对比分析。

解题思路提示

算法复杂度分析习题的解题方法论:

  1. 嵌套循环分析:从内到外逐层分析,外层循环次数乘以内层循环次数; 层嵌套循环通常为
  2. 三种情况分析:最好情况(最乐观的输入)、最坏情况(最不利的输入)、平均情况(所有输入的期望值,需要概率假设)
  3. 主定理应用:先识别 (子问题数)、(缩小因子)、(合并代价),再计算 ,最后判断属于三种情况中的哪一种
  4. 展开法验证:将递推关系展开若干层,寻找规律(等比数列),适用于验证主定理的结果或处理主定理不直接适用的情况
  5. 算法对比:关注时间复杂度的渐近阶、常数因子、实际适用条件(如数据规模、数值稳定性)

五、视频学习指南

视频资源

资源链接对应内容备注
Rosen 8e Section 3.3教材原文完整分析过程与例题英文教材
MIT 6.006 Introduction to AlgorithmsYouTube排序与搜索复杂度英文,MIT开放课程
Visualgo (visualgo.net)链接排序算法可视化动画直观感受不同算法的效率差异

六、教材原文

教材原文

“The time complexity of an algorithm can be expressed in terms of the number of operations used by the algorithm when the input has a particular size. The operations used to measure time complexity can be the comparison of integers, the addition of integers, the multiplication of integers, the division of integers, or any other basic operation.”

“A problem that is solvable using an algorithm with polynomial (or better) worst-case complexity is called tractable… A problem that cannot be solved using an algorithm with worst-case polynomial time complexity is called intractable.”

“The P versus NP problem asks whether NP, the class of problems for which it is possible to check solutions in polynomial time, equals P, the class of tractable problems. This is one of the most famous unsolved problems in the mathematical sciences. It is one of the seven famous Millennium Prize Problems. A prize of $1,000,000 is offered by the Clay Mathematics Institute for its solution.”


参见 Wiki

算法