c++ - 了解递归函数的执行顺序
问题描述
template <typename T>
T sum(stack<T>& s){
if (s.empty()){
return 0;
} else {
T first = s.top();
s.pop();
T total = sum(s)+first;
s.push(first);
return total;
}
}
上面的代码旨在递归地对任何给定类型 T 堆栈的元素求和,唯一的条件是堆栈的完整性必须在函数结束时恢复。意思是,我可以对堆栈进行更改以对元素求和,只要它处于与函数终止时传递它之前的状态相同的状态。
正如您将观察到的那样,给定的代码可以工作,但是我不理解递归调用和返回语句的控制流或执行顺序。当我看到这段代码时,我了解元素是如何求和的,但是我不明白对“s.push(first)”的调用如何将所有元素添加回堆栈。我很难理解为什么它不会只推送堆栈的最后一个元素然后返回总数。
我目前对其工作原理的理解是不完整的,并且可能存在缺陷,如下所示:因为每个 return 语句都返回到最近的调用者,所以当递归遇到基本情况并终止时,return 语句将以它们的方式支持递归调用堆栈直到它到达原始调用者,因此在每次移动时执行“s.push()”备份堆栈。
让我感到困惑的是堆栈为空后的执行顺序,我认为这是由于缺乏对函数递归备份调用堆栈的方式的理解。如果有人可以列出执行顺序并解释递归与递归调用下的操作的工作方式,我将不胜感激。谢谢!
解决方案
Your overall understanding is correct. You're only missing connecting the final dots.
The key point to remember is when a function returns, it returns to wherever it was called from. Recursive functions are no different in that fundamental respect. Recursive function calls work exactly the same way.
It will help to understand if you label each recursive call. Let's call the initial invocation of the recursive function "A
". When the recursive function calls itself, recursively, call that invocation of the recursive function "B
". Then it calls again, and that's "C
". Followed by "D
", and so on.
The key point to understand is that when a function returns, it returns to wherever it was called from. So, "D
" returns to "C
", which returns to "B
", and it returns to "A
".
Now look at your recursive function. When the stack had one value left, let's call it "D
", it removes the "D
" value from the stack and makes the recursive call "E
", which discovers that the stack is empty.
So it returns to "D
", which pushes the "D
" value back to the stack, which now has one value again. Then it returns to "C
", which pushes the "C
" value back to the stack, which now has the two original, last, values on the stack, in the same order.
In this fashion, the function calls unwind in reverse order from their original calling sequence, restoring the stack to exactly what it was, originally.
推荐阅读
- sql - 字符串或二进制数据将被截断 - 插入到 #temp 表时
- arrays - 更新嵌套数组 MongoDB 中的对象
- javascript - 在 jQuery 中计算从 php 获取的项目
- pandas - 使用多个布尔条件在 pandas 中标记行而不使用链接
- java - RecyclerView 适配器方法没有被调用 kotlin
- git - 将文件夹推送到新项目时 HTTP 基本访问被拒绝
- angular - Ag-grid:更新 filterParams 以更改可能的过滤器值
- android - 如何在 Android 的 sharedPreference 中附加数据
- java - 从 Java 中的字符串恢复列表
- java - 尝试在空对象引用上调用虚拟方法 'android.text.Editable android.widget.EditText.getText()'。EditText 已初始化