递归思想之如何理解汉诺塔问题
递归思想之如何理解汉诺塔问题
0x1 问题描述
有A,B,C三个柱子,将A柱子上的N个盘子(从大到小排列)移到C柱子上,每次只允许移动一个盘子,并且保证每个柱子上的盘子的排列都是从大到小。
0x2 递归算法
#include <iostream>
using namespace std;
void haoi(int n,char a,char b,char c)
{
if(n==1)
{
cout<<a<<"->"<<c<<endl;
return;
}
haoi(n-1,a,c,b);
cout<<a<<"->"<<c<<endl;
haoi(n-1,b,a,c);
}
int main()
{
haoi(3,'A','B','C');
}
0x3 算法分析及其理解
关于这个问题我看了许多文章,其中有一篇文章讲了一个变薄的道理,很形象说明了递归的本质,也就是我们代码看的是最上面的,然后递归下去,最后回溯上来,类似一个V字型的结构。为什么我会说变薄呢,其实我们可以这么理解,
假设当前n=3,我们把上面两块当成一个整体,那么对应n=2的操作是:
1.A->B
2.A->C
3.B->C
其实直接是这么写的
haoi(n-1,a,c,b); // cout<< A->B <<endl;
cout<<a<<"->"<<c<<endl;
haoi(n-1,b,a,c); //cout<< B->C <<endl;
但是很明显这里用的是haoi(n-1,a,c,b)
用到了递归
为什么呢,其实可以理解为递归过程就是为了cout<< A->B <<endl
做铺垫。
也就是说最后问题会简化为cout<< A->B <<endl
也就是可以忽略n-2个盘子
此时就是
最开始A:n-1
最终简化后就是:
A:2-1(从下到上有两个盘子) B:空 C:n-3(从下到上有n-2个盘子)(这个结果就是递归的结果)
每次调用递归就是一次简化过程(变薄过程,你完全可以忽略C放的是什么盘子,因为它是最大的)
最终简化的前一步简化就是:
A:32 B:空 C:n-4 这里2代表的是21
A:43 B:空 C:n-5 这里3代表的是321
….
A:n-(n-1) B:空 C:空 这里n-1代表是(n-1)-1
其实这个递归相比那种阶乘递归的难理解是因为这里是两个递归再交叉,导致人脑不能直接回溯,也就是多个子问题->父问题,而不是一个子问题->父问题。
但是按照简化的步骤来看,要做的操作永远是
1.A->B
2.A->C
3.B->C
所以代码就不难写出来了。