递归解决汉诺塔问题(原理图解+代码实现+递归讲解)

话不多说,我们直奔主题

1.递归算法的基本模式:终止条件+递推公式

int digui(int n)
{
	if (sth1)//sth1为终止条件
	{
		return sth2;//sth2通常为一个逻辑上很简单的值
	}
    else
    {
        return sth3;//sth3为递推公式,亦即规律
        //当然这只是一个简单的逻辑,格式上不能拘泥于此
    }
	
}

以递归实现斐波那契数列为例

1,1,2,3,5,,,  f(n)=f(n-1)+f(n-2),,,

终止条件即 当情况很简单时可以直接得到值,一般是n=1的情形,这时不需要再往下递归了,就算终止了哈哈

此处即 n<=2 时f(n)=1。所以

sth1: n<=2

sth2: 1

递推公式可以理解为我想得到f(n)的值,那我只需要得到f(n-1)+f(n-2)的值;如果我想得到f(n-1)的值,那么我只需要得到f(n-2)+f(n-3)的值。。。直到终止条件

此处即 sth3: f(n-1)+f(n-2)

完整代码

int feiBoNaQie(int n)
{
	if (n <= 2)
	{
		return 1;
	 }
	else
		return feiBoNaQie(n-1)+feiBoNaQie(n-2);
}

 2汉诺塔问题

我们先构建一个基本模型

有a b c三根柱子,初始时先定义a from;b mid;c to。我们的目标就是将a柱上的n个圆盘按照汉诺塔的规则移动到c柱上

 需要解释的是,from,mid,to是对于一个圆盘(或多个圆盘的整体)来说的,比如一个圆盘想从b柱到达c柱,那么对于该圆盘来说b柱为from柱,c柱为to柱,a柱为mid柱。

我们先看看有1,2个盘子的情形,显然

n=1;

a->c

n=2;

a->b  

a->c  

b->c

我们可以这样考虑:

n=2时,我们是先把第一个圆盘放在了mid柱(b),这样对a柱来说,就变成了只有一个盘子的汉诺塔问题,即从from柱(a)-->to柱(c);对于b柱来说,也变成了只有一个盘子的汉诺塔问题,即从from柱(b)->to柱(c)

   --->  

    --->      

这样我们就先找到了递归的终止条件:

当某柱上只有一个圆盘时,我们仅需将它从from柱移到to柱,注意此时的from柱不一定是a柱,to柱也不一定是c柱,从n==2的分析中我们应该就能看出端倪。

那么递归函数里的终止条件代码就可以这么写:

if(n==1)
{
    printf("%c-->&c\n",from,to);
}

代码里的from,to是代表a,b,c柱子的变量,但是我们目前也不知道对应关系哈哈,但是n肯定是圆盘的数量。

那么递推公式是什么?

当有两个圆盘时我们是把上面那个放在mid柱子,那有n个时我们仍当作两个处理。

1.把上面n-1个当作一个整体,放在mid柱子,

2.a柱一个圆盘放到c柱,

3.b柱n-1个圆盘(此时当作整体)放到c柱。

 

 

 对a柱上面的n-1个圆盘:a柱是from柱子,b柱是to柱子,c柱子是mid柱子;

对a柱下面的一个圆盘:a柱是from柱子,c柱子是to柱子,b柱是mid柱子;

所以现在的问题就变成了如何将上面n-1个圆盘放到b柱子上面

那么我们继续将这n-1个圆盘划分成两份,上面n-2个,下面一个。

按照两个圆盘的套路,我们要把上面n-2个移到mid柱子。思考,这时的mid柱子是哪根??

 还是b柱吗?答案是c柱。读者在这里可以先细想下是为什么???我就不解释了。。。

。。。

读者应该品出来递归的味道了吧

ok我们总结下n个盘子的规律

对于n 个盘子a-->c mid=b  需要三步:

1.先n-1个盘子a-->b mid=c

2.然后最下面那个盘子a->c mid=b,

3.最后n-1个盘子b-->c mid=a

对于n-1个盘子 a-->b  mid=c 需要三步:

1.先n-2个盘子a-->c mid=b

2.然后最下面那个盘子 a->b mid=c

3.最后n-2个盘子c-->b mid=a

。。。

然后就如此递归下去直到终止条件

并可以发现,

这两句话的第一步 from=上一层(盘子数+1)的from, to=上一层的mid, mid=上一层的to

                  第二步 from=上一层的from,to=上一层的to,mid=上一层的mid

                  第三步 from=上一层的mid, to=上一层的to,mid=上一层的from

所以这就是递归规律

所以我们假定递归函数

void digui(int n, char from,char mid,char to);

//声明

那么

对于n个圆盘的汉诺塔

要想digui(n,from,mid,to);

那么先 digui(n-1,from,to,mid)

然后 print("%c-->%c\n",from,to)

最后 digui(n-1,mid,to,from)

所以递归函数是

void digui(int n, char from, char mid, char to)
{
    if(n==1)
        printf("%c-->%c\n",from,to);
    else
    {
        digui(n-1,from,to,mid);
        printf("%c-->%c\n",from,to);
        digui(n-1,mid,from,to);
    }
}

作者水平有限,不太能很好地表达自己的想法。如有疑问或纰漏请不吝指教

求个关注和点赞吧  >--<

               

                        。。。

        

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值