hello algorithm chapter 2 / Iteration and recursion

Q: what is complexity?

A: 函数的操作数量与输入数据大小的数学关系。 例如,单循环函数的操作数量和输入操作数成正比,或者说成“线性关系”,单循环函数的复杂度就是 \(O(1)\)

迭代与递归 代表了两种完全不同的思考和解决问题的范式

  • 迭代:“自下而上”地解决问题。从最基础的步骤开始,然后不断重复或累加这些步骤,直到任务完成。
  • 递归:“自上而下”地解决问题。将原问题分解为更小的子问题,这些子问题和原问题具有相同的形式。接下来将子问题继续分解为更小的子问题,直到基本情况时停止(基本情况的解是已知的)。

features of recursion

  1. invoke stack

递归函数每次调用自身时,系统都会为新开启的函数分配内存,以存储局部变量、调用地址和其他信息等。这将导致两方面的结果。

  • 函数的上下文数据都存储在称为“栈帧空间”的内存区域中,直至函数返回后才会被释放。因此,递归通常比迭代更加耗费内存空间
  • 递归调用函数会产生额外的开销。因此递归通常比循环的时间效率更低
  1. tail recursion
  • 普通递归:当函数返回到上一层级的函数后,需要继续执行代码,因此系统需要保存上一层调用的上下文。
  • 尾递归:递归调用是函数返回前的最后一个操作,这意味着函数返回到上一层级后,无需继续执行其他操作,因此系统无需保存上一层函数的上下文

normal recursion

we put operation in parameter table in tail recursion

1
2
3
4
5
6
7
8
9
/* 尾递归 */
int tailRecur(int n, int res) {
// 终止条件
if (n == 0)
return res;
// 尾递归调用
// we put operation in parameter table in tail recursion
return tailRecur(n - 1, res + n);
}

tail recursion

1
2
3
4
5
6
7
8
9
10
/* 递归 */
int recur(int n) {
// 终止条件
if (n == 1)
return 1;
// 递:递归调用
int res = recur(n - 1);
// 归:返回结果
return n + res;
}

Notes: 许多编译器或解释器并不支持尾递归优化。例如,Python 默认不支持尾递归优化,因此即使函数是尾递归形式,但仍然可能会遇到栈溢出问题。

Iteration Recursion
Implemention 循环结构 函数调用自身
Time efficient 效率通常较高,无函数调用开销 每次函数调用都会产生开销
Memory usage 通常使用固定大小的内存空间 累积函数调用可能使用大量的栈帧空间
Applicable issue 适用于简单循环任务,代码直观、可读性好 适用于子问题分解,如树、图、分治、回溯等,代码结构简洁、清晰

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!