1002_尾递归为何没有层层递增的调用栈
尾递归
尾递归可以直接销毁调用栈(也有可能是每次递归都是用同一个栈)、而不使栈空间层层叠加。
先看尾递归代码
// 打印链表的每一个元素
1 void c_List_print_data(p_Node_t pList)
2 {
3 if(pList == NULL)
4 {
5 return;
6 }
7 printf("%d, ", pList->data);
8 c_List_print_data(pList->Next);
9
10 }
11
12 void main(void)
13 {
14 int x;
15 c_List_print_data(phead);
16 x = 1;
17 }
递归发生在第 8 条语句 c_List_print_data(pList->Next);,即 c_List_print_data() 函数作为调用者,去调用另一个函数(调用和自己代码一模一样的函数 c_List_print_data())、形成递归。
特别地、第 8 条语句是调用者的最后一条语句:发生递归调用时、调用者本身已经没有其他语句需要执行了,那么其中的局部变量都不会再被使用到了,这个调用栈就可以被销毁释放掉。
所以、我们可以在递归调用发生时、将调用者的调用栈销毁回收,同时给被调用者创建一个新的调用栈(也可以在刚销毁的位置创建、或者不销毁直接初始化后就使用)。
同时、在被调用者返回后、调用者将运行到第 9 行:调用者自己也将返回。
调用者和被调用者最终都返回到同一个地方(第 15 条语句),也就是说它们的返回地址可以设置成一样,或者说可以不修改返回地址,也不新增新的一样的返回地址去多次返回,只需要在最后一次被调用者返回后(执行到退出条件)、做一次返回即可。
具体如何实现、就看不同编译器如何实现了。
图示说明:
假设链表有2个元素:

第一次进入 c_List_print_data() 时、调用栈如下:

在执行前面 7 条语句的过程中,这个调用栈都不变。
执行第 8 条语句时、第二次调用 c_List_print_data()。
假如不销毁当前调用栈,并创建新的调用栈,那么调用栈情况将会是下面这样:

但是现在、我们在第二次调用 c_List_print_data() 前、就先销毁调用栈,再调用 c_List_print_data(),并为其创建新的调用栈,那么调用栈情况如下:

第一次调用 c_List_print_data() 时的局部变量(50)已被销毁,取而代之的是现在的(90)。
最后一次递归时的调用栈如下:

这次调用返回后、整个递归就执行完毕并返回,程序将执行第 16 条语句。

浙公网安备 33010602011771号