這道題的關鍵在于理解遞歸轉非遞歸與 “是否用棧” 的本質邏輯,和 “局部變量” 無關,核心看遞歸的調用上下文是否需要保存。
一、遞歸的本質:依賴 “調用棧”
遞歸函數執行時,系統會用調用棧保存:
- 每層遞歸的參數、返回地址、局部變量(不管是不是局部變量,只要遞歸嵌套,就需要保存上下文)。
比如經典的遞歸求和:
int sum(int n) {if (n == 1) return 1;// 遞歸調用,sum(n-1) 依賴上一層的 nreturn n + sum(n-1);
}
這里?sum(3)
?調用?sum(2)
,sum(2)
?調用?sum(1)
,每層的?n
(局部變量)會存在棧里。
二、“是否用棧” 的關鍵:是否需要模擬 “調用棧”
遞歸轉非遞歸時,不管有沒有局部變量,只要遞歸有多層嵌套(需要保存上下文),就可能需要用棧手動模擬調用棧。
反例 1(無局部變量,但需要棧):
// 遞歸打印 1~n,無局部變量(除了參數)
void print(int n) {if (n == 0) return;print(n-1);printf("%d ", n);
}
轉非遞歸時,仍需用棧保存?n
?的值(模擬調用棧的嵌套),否則無法按順序打印?1 2 3
。
反例 2(有局部變量,但無需棧):
// 尾遞歸:遞歸調用在最后,無額外計算
int tail_sum(int n, int res) {if (n == 0) return res;// 遞歸調用后直接返回,無需保存復雜上下文return tail_sum(n-1, res + n);
}
這種尾遞歸可直接轉迭代(用變量代替棧):
int iter_sum(int n) {int res = 0;for (int i = 1; i <= n; i++) {res += i; // 無需棧,迭代累加}return res;
}
此時,即使有局部變量(res
?是函數參數,類似局部變量),也不用棧。
三、題目邏輯錯誤點
題目說 “只有使用局部變量的遞歸,轉非遞歸才必須用棧”,但實際:
- 不用局部變量的遞歸(如?
print
?函數),轉非遞歸可能也需要棧; - 用局部變量的遞歸(如尾遞歸?
tail_sum
?),轉非遞歸可能不需要棧。
“是否用棧” 和遞歸的嵌套結構(是否需要保存上下文)?有關,和 “是否用局部變量” 無關。因此題目說法?錯誤