遞歸代碼簡潔優雅,但對於階乘、斐波那契等問題,遞歸往往是效能殺手。本文通過對比揭示遞歸的堆棧開銷問題,並給出高效的迭代替代方案。
long factorial_recursive(int n) {
if (n <= 0) return 1;
return n * factorial_recursive(n - 1); // n 次函數調用
}
long factorial_iterative(int n) {
long result = 1;
while (n > 1) {
result *= n;
n--;
}
return result; // 單循環,O(1) 空間
}
long fibonacci_recursive(int n) {
if (n <= 2) return 1;
return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2); // 指數級調用
}
計算 fib(40) 需約 3 億次調用,耗時秒級。
long fibonacci_iterative(int n) {
if (n <= 2) return 1;
long a = 1, b = 1, c;
for (int i = 3; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return b; // O(n) 時間,O(1) 空間
}
| 算法 | 時間複雜度 | 空間複雜度 | 實測耗時 |
|---|---|---|---|
| 遞歸斐波那契 | O(2^n) | O(n) | ~3 秒 |
| 迭代斐波那契 | O(n) | O(1) | < 1 微秒 |
| 遞歸階乘 | O(n) | O(n) | 微秒級 |
| 迭代階乘 | O(n) | O(1) | 納秒級 |
// 尾遞歸版階乘(編譯器優化後等價於迭代)
long factorial_tail(int n, long acc) {
if (n <= 1) return acc;
return factorial_tail(n - 1, n * acc); // 遞歸調用是最後操作
}
// 調用:factorial_tail(5, 1)