其实一直到现在我都不知道自己有没有学会递归,因为做题的时候我也是避重就轻挑着我擅长的题做,所以这方面一直没有得到突破性的提高。
因为递归的概念很好理解,但是实际操作起来就会让人很迷糊,比如说汉诺塔。
但昨天老师在群里面分享了四节递归课程,我决定重新拾起我以前没有干完的活。
那么我们就先从汉诺塔这个经典的递归开始学吧,以前我在看这道题的时候,总是会想着去模拟这整个过程。
就比如说我会去网上下载一些汉诺塔的小游戏玩,美曰其名为模拟过程加深理解,其实就是打着幌子在玩游戏。
或者我会在纸上面画图模拟整个过程,而且时常画着画着就画糊涂了。
可能你很疑惑,为什么要模拟过程呢?
因为我不理解他为什么只在调用他自己时把参数的位置改一改就可以得到全部过程。
但现在看来,着实没有必要,我们只需要知道我们得把这n-1个盘子移动到b盘,再把最底下的盘子移动到c盘,再把n-1个盘子移动到c盘就好了。
也就是说,我们把它分为两个整体,n-1个盘子为一个整体,最底下的盘子是一个整体,但是那n-1个盘子是怎么移动的呢?
我能告诉你的只有他会重复之前的步骤,把n-1分解成为n-2个盘子和第n-1个盘子,n-2个盘子怎么移动的呢,分解成n-3个盘子和第n-2个盘子呗,后面的也以此类推。
直到我们分解到最顶上那个最小的盘子的时候,只需要把它从a盘拿到c盘就可以了(这是一个出口,也就是说我们的栈已经满了,需要一个判断出口,把那些堆进栈的东西都一个个拿出去)
那么现在我们知道该怎么把这一个大问题分解成几个小问题,也知道出口是什么,代码就很好写了。
#include<iostream> #include<cstdio> using namespace std; int a,ans=0;//ans是用来记录总共移动的次数的 void hnt(int n,char a,char b,char c){//递归函数 if(n==1){//出口判断 ans++;//移动的时候ans就+1 cout<<a<<" "<<c<<endl;//等到最后一个小盘子的时候,我们就直接让它从a盘去c盘 } else{ hnt(n-1,a,c,b);//分解问题到n-1 ans++;//移动的时候ans就+1 cout<<a<<" "<<c<<endl;//解决完n-1就只剩第n个盘子了,我们就把第n个盘子从a盘直接拿到c盘 hnt(n-1,b,a,c);//再把这n-1从b盘上面转到c盘上面 } } int main(){ cin>>a;//输入要移动的盘子数量 hnt(a,'A','B','C'); cout<<ans<<endl;//输出一共需要移动多少次 return 0; }
为什么明明我们需要用这三个柱子来进行操作,可是输出的时候只用输出a和c呢?
不知道你有没有注意到我们在进行递归的时候,调用函数的参数我们让他改变了。
所以a、b、c每个变量里面的字符都不一样了,所以只要输出a和c就可以达到我们想要的结果。
你可能会想,我们把他改变了,他会是怎么运行的呢?要不我计算试试看?
那么我只能告诉你,千万不要计算,不要去深究这个问题。因为你会发现你越算越糊涂,越算越不会。
只需要知道这个为什么要这样算,不需要知道她是怎么算的。
也就是说我们只要计算方法和结果,过程不重要。