浅谈函数递归汉诺塔

前言

谈到递归相信大家都会想起一个特别经典的问题——汉诺塔。本文浅谈一下自己对汉诺塔问题的简单理解和对该问题简单思考。如有错误,请多指教!


一、汉诺塔问题是什么?

汉诺塔问题源自印度一个古老的传说,印度教的“创造之神”梵天创造世界时做了 3 根金刚石柱,其中的一根柱子上按照从小到大的顺序摞着 64 个黄金圆盘。梵天命令一个叫婆罗门的门徒将所有的圆盘移动到另一个柱子上,移动过程中必须遵守以下规则:
每次只能移动柱子最顶端的一个圆盘;
每个柱子上,小圆盘永远要位于大圆盘之上;

二、思考方式

1.大体思考

这个问题猛然一看感觉无从下手,我们不妨将问题简单抽象出来。我们可以简单举个小例子:
当盘子为3的时候,(为了便于描述:因为规则是大盘子在下,所以盘子从下往上命名为3 2 1;柱子状态为空为0)

起始状态
A: 3 2 1;(从下往上)
B:空
C:--------------
A:3 2
B:0
C :1

A: 3 
B: 2
C: 1

A:3
B:2 1
C: 0

A:0
B:2 1
C:3 ;

A:1
B:2
C:3

A:1
B:0
C:3 2

A :
B :
C : 3 2 1
----------------

Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C

从上面例子简单分析:
第一步:先移动1从A到C柱上,
第二步:现在把2从A移动到B柱上,
第三步:把1从C移动动到B;
第四步:把3从A移动到C;
第五步:把1从B移动到A;
第六步:把2从B移动到C;
第七步:把1从A移动到C;
我们先通过抽象思考一下这个移动盘子的最后一步肯定是:前N-1个盘子一定在C柱子上(或者B都行只是一个代号用来举例),把此时另外某个柱子上一定有一个1号盘子,只需把这个1号盘子移动到C柱上就行了。那么前N-1个盘子是怎么到C柱的,一定有N-2个盘子移动到了C柱上,只需移动1号盘子到C柱上,便可得到N-1个盘子到C柱上,这样依此类推可以把n-1,n-2,n-3,…看成一个整体,直到把n分解成1这种简单求解的问题。

2.简单归纳

通过上述的简单思考,其实我们可以把这个相对复杂的问题简化成规模较小的问题。这种处理问题的思想叫做分治思想。分而治之,把大问题转化成小问题。但其实不难看出,该问题的处理方法都是相同的,都是重复的计算步骤,因此分治思想的前提是保证划分出来的小规模问题处理方法都是相同的。如果该问题把简单转成数学模型来求解的话,可以很自然的把n个盘子移动次数设为F(n),当A柱子上有n个盘子时候,A柱上除了n号盘子以外的前n-1个盘子都会通过某种方式移动到B柱子上;A上最大的盘子N号盘子移动一次到C柱,B上的n-1个盘子通过某种方式移动到C柱上,所以一共有2F(n-1)+1次,当n=1时,可以明显看出只需移动一次,于是即可得到表达式F(n)=2F(n-1)+1,F(1)=1;这便推导出了递归表达式,有了该式子可以很容易写出递归函数。

3.函数递归的实现

写递归首先找到边界条件,也就是递归出口,这样才不会死递归,递归出口就是n=1的时候,直接一次移动。当n>1时实际上是上面表达式中调用了两次F(n-1),所以在写递归时须在函数内部写两次(n-1)的情景。

#include<stdio.h>
void hanoi(int n, char A, char C, char B)
{
    if (n == 1)
        printf("Move disk %d from %c to %c\n", n, A, C);
    else
    {   
        hanoi(n - 1, A, B, C);
        printf("Move disk %d from %c to %c\n", n, A, C);
        hanoi(n - 1, B, C, A);
    }
}
int main()
{
    int n;
    scanf("%d", &n);
    hanoi(n, 'A', 'C', 'B');
    return 0;
}

三.总结

其实,如果有兴趣的话是可以推导出证明出来F(n)的详细表达式的,因为F(1)=1,F(n)=2*F(n-1)+1;
可以得到F(1)=1,F(2)=3,F(3)=7,F(4)=15…其实F(n)=2^n-1。这是可以证明出来的,但是以上主要还是想介绍函数递归的使用,以及用分治思想来处理解决一些问题。以上便是我的拙见,如有错误,请多指教!

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值