简单总结一下递归。递归就是在运行的过程中调用自己。递归需要有一个出口,如果无限递归是没有意义的,而且递归到一定程度,程序就会由于栈内存溢出导致程序报错。
我们先来看段代码:建议大家先思考这个代码在控制台输出的结果是什么?先不要看下面的结果。
经过一番思考后,相信你已经有了自己的答案,接下里就揭晓正确答案了哦。我们先来看看程序运行的结果。
#include <iostream>
using namespace std;
void sum(int num)
{
if (num > 10) return;
cout << num <<endl;
num++;
sum(num);
cout << "end" << num << endl;
}
int main()
{
sum(1);
return 0;
}
看到这个结果后,小编请大家在思考几个问题:
- 为什么不是输出的数字后面没有直接输出“递归后”这三个文字,而是在后面集中输出了十次“递归后”?
- 造成这种结果的原因是什么?
- 你的想法是不是跟第1个问题一样?
如果你还没思考上面的几个问题,建议想想再往下看。这对你理解递归很好的帮助!
首先程序运行,首先从main方法开始压栈执行,先执行test(1);这行代码,然后进入方法后一直递归使用test方法,但是一运行到调用递归方法时,都会重新复制一份test方法压栈执行,但是之前的test方法还是在栈中,因为一碰到递归就会一直复制递归方法到栈中执行,一直到递归出口。
就这样一直到a>10时,到了递归出口,当参数a大于10时,此时栈内存中就只有一个main方法,十个递归方法。这时程序开始执行test(10)中未执行的代码,也就是递归方法后的输出语句。test(10)走完后,该方法已经运行完毕弹栈消失。接着运行test(9)中未运行的语句。以此类推,我们不难得到这样的结论:每次递归都会从方法区中复制一份方法到栈中压栈执行,这样就会一直调用递归的方法,一直压栈。直至到了递归出口,从最后进栈的那个递归方法运行递归后面的其他语句,运行完弹栈消失,然后一个接一个方法执行并且弹栈消失。也就是说最先输出的是最晚进栈的递归方法,这就是栈结构先进后出的特点。
看到这,我想大部分人已经懂了一点。但是还有有点不清晰,所以我在最后在以图片配视频的方式来帮助大家理解本文核心。我暂时认为大家不清晰的点有以下几点:
- 弹栈消失的过程是什么样?
- 第一个进栈的递归方法后的输出语句在其他递归进栈的这段时间为什么不往下运行了?
第一个问题采用动态的视频加图片的形式解答,这样更容易理解。(感谢君哥提供工具)通过视频我们可以看出最后进栈的是最先出栈的。这就是所谓的先进后出!
tips:原网页是英文的,翻译后就成了一些看不懂的东西,忽略。
第二个问题,由于程序运行是从上往下的,所以一运行到递归就走递归的方法,实际第一个方法很痛苦,它一直在叫:“上面的哥们能快点吗?你们压着我运行不了,我很难受!”。所以早进栈执行的方法一直在等待,等待什么呢?等待他上面的递归方法弹栈消失,只有他上面的方法执行完才能轮到他。毕竟它上面压着九个哥们呢,这九个哥们不起来,最底下的你能起得来?
综上所述:
递归后的语句是能够执行的,但是执行顺序是到递归出口后,从最后一个进栈执行的方法执行递归后的语句,每执行完一个方法就弹栈消失,然后依次类推。