数据结构——算法效率的度量(时间复杂度与空间复杂度)

算法的优劣主要体现在两个方面:运行所需的时间占用的存储空间。为了在理论上比较不同算法的效率,我们需要找到一种通用的度量方法。

(1)时间复杂度

1)基本概念

在分析算法时,我们常常统计基本操作 (例如比较、赋值、加法)的执行次数。假设输入规模为 nnn,算法中基本操作的执行次数记为 T(n)T(n)T(n)。由于不同机器的运行速度不同,我们不关心具体的秒数,而是关心随着 nnn 增大,运行次数如何增长

于是,我们引入渐近时间复杂度

T(n)=O(f(n)) T(n) = O(f(n)) T(n)=O(f(n))

其中,f(n)f(n)f(n) 表示一个简单的函数(如 nnn、n2n^2n2、log⁡n\log nlogn),用来描述增长趋势,忽略常数因子和低阶项。

2)例子

考虑下面的简单查找:

text 复制代码
i = n
while(i > 0 && A[i] != k) 
    i = i - 1
  • 如果数组中没有值为 kkk 的元素,循环要执行 nnn 次,时间复杂度为 O(n)O(n)O(n)。
  • 如果最后一个元素刚好等于 kkk,循环只执行 1 次,复杂度为 O(1)O(1)O(1)。

这说明:同一个算法可能有最好情况最坏情况平均情况 三种时间复杂度。为了保证算法在任何情况下都不会太差,我们通常取最坏情况复杂度作为衡量标准。

3)规律总结

常见的复杂度大小关系如下:

O(1)<O(log⁡n)<O(n)<O(nlog⁡n)<O(n2)<O(2n)<O(n!) O(1) < O(\log n) < O(n) < O(n\log n) < O(n^2) < O(2^n) < O(n!) O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(2n)<O(n!)

在实际题目中,我们主要关心如何根据循环次数递归式来判断复杂度。例如:

  • 顺序执行:取最大项;
  • 嵌套循环:次数相乘;
  • 二分法:每次规模减半,复杂度为 O(log⁡n)O(\log n)O(logn)。

(2)空间复杂度

1)基本概念

空间复杂度 S(n)S(n)S(n) 用来度量算法在运行过程中额外需要的存储量。除了存放输入数据所需的内存外,算法往往还需要一些辅助空间。

2)常见情况

  • 常量级空间 :只用到少量变量,例如交换两个数。复杂度 O(1)O(1)O(1)。
  • 与规模相关的辅助空间 :如排序时需要一个额外数组,复杂度可能达到 O(n)O(n)O(n)。
  • 递归调用的栈空间 :递归深度为 ddd,则辅助空间为 O(d)O(d)O(d)。例如快速排序平均为 O(log⁡n)O(\log n)O(logn),最坏为 O(n)O(n)O(n)。

(3)时间与空间的权衡

有些算法通过"增加空间"来换取"减少时间"(如哈希表查找只需 O(1)O(1)O(1)),有些算法则通过"减少空间"而增加时间(如原地排序节省内存,但操作更多)。这种时间---空间权衡思想是算法设计的重要原则。


小结

  • 时间复杂度反映了算法随输入规模增长所需的运算次数,是算法效率的主要指标。
  • 空间复杂度反映了算法需要的额外内存,是评价实现可行性的重要因素。
  • 考研题目中常要求推算循环与递归的时间复杂度,并比较不同算法在时间与空间上的优劣。