从代码出发理解时间复杂度与空间复杂度

从代码出发理解时间复杂度与空间复杂度

算法分析不追求算出程序运行多少毫秒,而是判断:当输入规模 N 变大时,运行时间和额外内存以什么速度增长。时间复杂度看基本操作的执行次数,空间复杂度看算法额外占用的存储空间。

一、为什么不能只看运行时间

同一段程序在不同电脑、编译器和输入数据上耗时不同。用输入规模 N 的函数来描述增长趋势,比某次运行的秒数更稳定,也更适合比较算法。

递归求斐波那契数是常见例子。它会反复计算相同的子问题,N 小时看不出代价,N 一大,调用次数就迅速膨胀------这正是复杂度分析要提前揭示的风险。

二、用大 O 表示法抓住主要增长项

大 O 表示法只保留决定增长速度的部分:

  1. 常数统一记为 1;
  2. 只保留最高阶项;
  3. 去掉最高阶项前的常数系数。

若一个函数的基本操作次数为 N² + 2N + 10,当 N 足够大时,N² 决定整体增长趋势,因此时间复杂度记为 O(N²)。

三、从代码判断时间复杂度

1. 双层循环:O(N²)

c 复制代码
for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
        // 基本操作
    }
}

外层循环执行 N 次,每次又执行 N 次内层循环,核心操作约执行 N×N 次,所以是 O(N²)。循环前后的少量常数操作不改变结论。

2. 单层循环:O(N)

代码只从头到尾遍历一次长度为 N 的数据,核心操作次数与 N 成正比,时间复杂度就是 O(N)。若分别遍历长度为 N 和 M 的两组数据,应写成 O(N+M),不能在没有关系的情况下把 M 偷换成 N。

3. 固定次数循环:O(1)

c 复制代码
for (int i = 0; i < 100; ++i) {
    // 基本操作
}

循环次数固定为 100,不随输入规模变化,因此记为 O(1)。O(1) 并不表示只执行一次,而是执行次数是常数。

4. 二分查找:O(log N)

二分查找每比较一次,就把待查区间缩小一半。经过 k 次后,区间规模约为 N/2ᵏ;当区间缩小到 1 时,k≈log₂N,因此复杂度为 O(log N)。

5. 冒泡排序:最坏 O(N²)

冒泡排序要进行多轮相邻元素比较。最坏情况下,比较次数的数量级为 N²,因此通常记为 O(N²)。

6. 递归:既看调用次数,也看调用深度

递归阶乘会沿着 N、N-1、N-2......一直调用到终止条件,调用次数与 N 成正比,时间复杂度为 O(N)。朴素递归斐波那契会分裂出大量重复调用,时间复杂度可达 O(2ᴺ)。

四、最好、平均与最坏情况

同一算法可能因为输入不同而执行不同次数。以顺序查找为例:

  • 第一个元素就命中:最好 O(1);
  • 目标在中间:平均仍是 O(N);
  • 目标在末尾或不存在:最坏 O(N)。

工程分析通常优先关注最坏情况,因为它给出了资源消耗的上界。

五、空间复杂度怎么看

空间复杂度衡量的是额外空间随 N 的增长趋势,不是程序本身占用的全部内存。

  • 只使用少量局部变量:O(1);
  • 动态申请 N 个元素的数组:O(N);
  • 递归调用深度为 N:调用栈需要 O(N) 空间。

递归函数即使每一层只定义一个常量级变量,所有尚未返回的栈帧叠加后,仍可能产生线性空间开销。

六、常见复杂度的增长顺序

从增长较慢到较快:

O(1) < O(log N) < O(N) < O(N log N) < O(N²) < O(2ᴺ) < O(N!)

N 很大时,复杂度级别的差异会远远超过常数优化带来的收益。先选对算法级别,再讨论局部优化,通常更有效。

七、实用分析清单

拿到一段代码时,可以依次检查:

  1. 输入规模 N 代表什么;
  2. 最频繁的基本操作是什么;
  3. 循环是否嵌套,边界是否依赖 N;
  4. 每次迭代是否把问题规模减半;
  5. 递归产生多少次调用,最大调用深度是多少;
  6. 是否申请了随 N 增长的数组、链表或其他辅助空间;
  7. 结论描述的是最好、平均还是最坏情况。

复杂度分析的核心不是背公式,而是建立"代码结构---执行次数---增长趋势"之间的对应关系。

相关推荐
白帽攻防录1 小时前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt
小O的算法实验室2 小时前
IEEE TEVC,基于精确与DQN群智能调度方法用于多目标异构USV
算法
字节跳动的猫3 小时前
LikeShop 积分体系全链路改造:获取规则、订单抵扣与积分商品兑换二开
运维·数据结构
可乐ea3 小时前
AI Agent 工具调用准确性评测:选择错误与参数错误分开测
大数据·人工智能·算法·大模型·工具调用·ai智能体·agent评测
上位机妹子3 小时前
C 语言 数组删除指定元素(快慢指针法)
c语言·数据结构·算法
心中有你02143 小时前
【路径规划】A*寻路算法最通俗易懂讲解(C语言完整实现+详细注释)
c语言·开发语言·算法
papaofdoudou4 小时前
初中数学-整数整除判定法全解:从 2 到 19 的方法、依据与证明
算法
让学习成为一种生活方式4 小时前
啤酒花基因组与重测序--Nature Communications
人工智能·算法
l1t4 小时前
DeepSeek总结的OpenZL压缩变换器
c++·算法