算法复杂度分析代码运行时时间与空间消耗随输入规模增长的趋势,用大O记号描述最坏情况下的增长上界,直接影响大数据量下的性能表现。

算法复杂度分析的是代码运行时对资源(主要是时间与空间)的消耗随输入规模增长的变化趋势,它不关心具体耗时多少毫秒,而是看当数据量变大时,执行时间或内存占用会“快还是慢地增长”。这直接决定程序在处理大量数据时是否卡顿、崩溃或响应迟缓。
时间复杂度:看代码“跑多快”
时间复杂度描述的是基本操作(如比较、赋值、简单计算)的执行次数与输入规模 n 的关系。常用大 O 记号(O(n)、O(n²)、O(log n) 等)表示最坏情况下的增长上界。
- O(1):常数时间,比如访问数组某个下标、对象属性读取,无论 n 多大都只做一次操作
- O(log n):对数时间,典型如二分查找,每次把问题规模砍掉一半
- O(n):线性时间,比如遍历一个数组,操作次数和元素个数成正比
- O(n²):平方时间,常见于两层嵌套循环,n=1000 时可能执行百万次操作
- O(2ⁿ) 或 O(n!):指数/阶乘级,小数据还能忍,n=20 就可能卡死,应极力避免
空间复杂度:看代码“吃多少内存”
空间复杂度衡量的是算法运行过程中临时占用的额外存储空间大小,同样以输入规模 n 为变量。它不包括输入本身占的内存,只算新申请的部分。
- 递归函数容易忽略隐式栈空间 —— 每次调用都压栈,深度为 n 时空间复杂度就是 O(n)
- 创建新数组、对象、Map/Set 等结构,要预估其容量是否随 n 增长而线性/平方增长
- 原地排序(如快排的 partition 过程)比新建数组排序(如归并排序的辅助数组)更省空间
为什么它真实影响执行效率?
现代 CPU 和内存虽快,但物理限制没变:CPU 每秒执行指令数有限,内存带宽和容量也有限。当算法复杂度高,输入稍大,资源消耗就非线性飙升。
立即学习“Java免费学习笔记(深入)”;
- O(n) 和 O(n²) 在 n=10⁵ 时差距巨大:前者约 10⁵ 次操作,后者达 10¹⁰ 次 —— 即使每条指令 1ns,也要 10 秒以上
- 前端场景中,O(n²) 的列表搜索或去重,在渲染上千条数据时会导致页面卡顿甚至假死
- Node.js 后端若用 O(n³) 处理用户行为日志聚合,请求延迟暴涨,可能触发超时或拖垮服务
怎么快速判断一段 JS 代码的复杂度?
不用背公式,抓住两个关键:循环嵌套层数 和 递归调用深度,再看每次迭代/递归处理的数据规模如何变化。
- 单层 for / while 循环 → 通常是 O(n)
- 两层 for 套着走,且内层从头到尾扫 → O(n²);若内层只扫固定次数或折半 → 可能是 O(n log n)
- 递归函数,每次把问题拆成一半(如二分)→ O(log n);每次拆成 n−1(如斐波那契朴素递归)→ O(2ⁿ)
- 使用 Set/Map 查找、删除是 O(1),用数组 indexOf 或 includes 是 O(n),选错数据结构会让本该 O(n) 的逻辑变成 O(n²)
不复杂但容易忽略。写代码时多问一句:“如果数据翻十倍,这段逻辑会慢多少?”答案往往就在复杂度里。











