为什么递归返回时堆栈中的项目没有立即弹出?

时间:2019-06-22 02:03:25

标签: recursion stack

好的,这可能是一个愚蠢的问题。但我认为,只要您退货,堆栈中的物品就会弹出。但是在递归的情况下,堆栈中的项目会不断堆积,直到到达基础案例为止。然后它开始弹出。我想知道为什么会这样。

而且,什么时候项目才从堆栈中弹出?

谢谢

2 个答案:

答案 0 :(得分:0)

例如:

def bar(n):
    if n > 0:
        print(n)
        return bar(n-1)
    return 'end'

return bar(n-1)语句中,我们首先执行bar(n-1),然后返回the return value中的bar(n-1)

执行bar(n-1)时,除非n > 0不再是True,否则我们将遇到类似的情况。

这就是为什么我们可以递归。

也许我的解释很无聊,我想与您分享一个visualized link您真的想看看

答案 1 :(得分:0)

我将通过“ item”进行假设,您指的是函数call stack的堆栈框架,而不是stack data structure中的item元素(其作用类似于调用堆栈)。我希望消除有关调用堆栈工作方式的困惑。

还要注意,thread中的每个process都有自己的调用堆栈。现在,假设我们正在使用一个具有运行中执行线程的单个进程。


递归函数是一个调用自身的函数。每当调用函数时,到达函数调用指令的线程都会创建一个堆栈框架。堆栈帧是一块内存,其中包含执行被调用函数所需的所有数据(变量,参数等)。该框架被“推送”到调用堆栈的顶部。当前正在执行调用的函数将暂时挂起,并且堆栈指针将移至新帧,然后执行该新帧。

在没有基本情况或函数不再进行递归调用的条件状态下,递归将无限期进行。发生这种情况时,操作系统会在超过堆栈使用量(通常为1 MB)时发送一个终止该进程的信号。

到达基本情况并执行函数中的最后一行代码后,线程开始从上至下解析堆栈框架,并在完成执行后将其从堆栈中弹出(它们可能会做更多的工作或进行其他递归操作)电话)。

弹出窗口表示释放与框架关联的内存,处理返回值,将堆栈指针移回调用方并恢复执行调用的位置。

这是一个使用C和Python编写的示例程序,其中包含一个递归函数和一个图:

#include <stdio.h>

void count_to(int n) {
    if (n > 0) {
        count_to(n - 1);
    }

    printf("%d\n", n);
}

int main() {
    count_to(4);
    return 0;
}
def count_to(n):
    if n > 0:
        count_to(n - 1)

    print(n)

count_to(4)

这是程序的输出:

0
1
2
3
4

这是执行期间调用堆栈的样子:

[count_to(4)]  <-- top of call stack/stack pointer
[main]         <-- bottom of call stack
[count_to(3)]  <-- 
[count_to(4)]  
[main]         
[count_to(3)]  <--
[count_to(4)]
[main]         
[count_to(2)]  <-- 
[count_to(3)]
[count_to(4)]
[main]         
[count_to(1)]  <--
[count_to(2)]
[count_to(3)]
[count_to(4)]
[main]         
[count_to(0)]  <--
[count_to(1)]
[count_to(2)]
[count_to(3)]
[count_to(4)]
[main]         

目前,尚未打印任何内容。该线程刚刚将函数调用添加到堆栈中。但是一旦我们调用count_to(0),递归就会停止。当我们弹出堆栈帧时,每个函数将打印其本地值n并返回其调用方。

print(0)
return

[count_to(1)]  <-- 
[count_to(2)]
[count_to(3)]
[count_to(4)]
[main]         
print(1)
return

[count_to(2)]  <-- 
[count_to(3)]
[count_to(4)]
[main]         
print(2)
return

[count_to(3)]  <--
[count_to(4)]
[main]         
print(3)
return

[count_to(4)]  <--
[main]         
print(4)
return

[main]         <--

最后,执行返回到main,然后退出。


我建议阅读Wikipedia的文章,例如stack-based memory allocationcall stack,并编写许多微型递归程序(例如此处的示例),以了解它们的工作原理。