一年前,老师用斐波那契数列引领我走进递归的殿堂,同一天,用汉诺塔扼杀了我对递归的好感。。。。。。
今天翻开算法书本来想看看有哪些经典问题被遗漏时,看到了这个汉诺塔,我才想起来当初老师讲这个问题的时候我没听懂,问题被搁置了,今天看见我才想起来,对于现在的我肯定没什么挑战,但是当初刚学递归的时候,真被它弄傻了。
看一下题目吧:
总的来说就是最终将所有圆盘都移动到c上面。移动过程中大圆盘不能在小圆盘上面,每次只能移动一个圆盘。
思考一下,将所有圆盘都移动到c上面,那么肯定需要将[1,n-1]圆盘都移动到b上面,然后a上的最大的圆盘n移动到c上面;然后的问题就变成了将[1,n-1]圆盘从b上借助a移动到c上面。
如果说void Hanoi(int n, char x, char y, char z)是我们的函数,表示将n个圆盘从x上借助y移动到z上面。那么我们肯定是按照刚才分析的,
(1)一开始调用该函数是Hanoi(n, a, b, c)表示将n个圆盘从a上借助b移动到c上。
(2)如果我们完成步骤(1)必须完成先将[1,n-1]圆盘从a上借助c移动到b上(因为只有这样,n圆盘才能从a拿到到c上),调用函数就是Hanoi(n-1,a,c,b),表示将[1,n-1]圆盘从a上借助c移动到b上。
(3)完成步骤1之后,我们要做的就是将b上的[1,n-1]圆盘从b上借助a移动到c上。这个和起初问题一模一样,只不过起初问题是从a借助b移动到c,现在是从b借助a移动到c。
看代码:
首先我们肯定希望n个圆盘从a上借助b,移动到c上
int main()
{
Hanoi(n,a,b,c);//①这个调用表示我们想要将n个圆盘从a上借助b移动到c上
return 0;
}
剩下的就是Hanoi这个函数了。如果我们要完成将n个圆盘从x上借助y移动到z上,那么肯定需要从x上借助z,将[1,n-1]这些圆盘移动到y上,如下步骤②;移动过后,我们需要将n圆盘从x上拿到z上,如下步骤③;然后,我们需要将b上的[1,n-2]圆盘从y上借助x移动到z,如下步骤④后面就是重复步骤了。注意递归出口,当Hanoi中的n为0时,返回。
void Hanoi(int n, char x, char y, char z)//注意这个n是表示n个圆盘
{
if(n == 0) return;
Hanoi(n-1, x, z, y);//步骤②
move(n, x, z);//步骤③ 注意这个n是表示第n个圆盘
Hanoi(n-1, y, x, z);//步骤④
}
还剩一个move函数没写,move函数就是简单的将一个圆盘从一个柱子上面移动到另一个柱子上面而已。
void move(int n, char src, char tar)
{
printf("将%d从%c移动到%c:%c->%c\n", n, src, tar, src, tar);
}
综合代码:
int g_num = 1;
void move(int n, char src, char tar)
{
printf("第%d步:将%d从%c移动到%c:%c->%c\n", g_num++, n, src, tar, src, tar);
}
void Hanoi(int n, char x, char y, char z)//注意这个n是表示n个圆盘
{
if (n == 0) return;
Hanoi(n - 1, x, z, y);//步骤②
move(n, x, z);//步骤③ 注意这个n是表示第n个圆盘
Hanoi(n - 1, y, x, z);//步骤④
}
int main()
{
Hanoi(3, 'a', 'b', 'c');//①这个调用表示我们想要将n个圆盘从a上借助b移动到c上
return 0;
}
运行结果;