轻松玩转递归,汉诺塔

递归的定义

谈到递归的定义,可以这样描述,假如一个函数或者子程序,是由自身·所定义或调用的,就称为递归

递归的条件

1、一个是可以循环执行的过程
2、一个是结束递归的条件

递归的分类

1、直接递归:指在递归函数中允许直接调用递归函数本身,就称为直接递归
2、间接递归:指在递归函数中如果调用其他递归函数,再从其他递归函数调用回原来的递归函数,就称为间接递归

递归示例

1、阶乘

n! = n * (n-1) * (n-2) … *1
可以分解为
n! = n * (n-1)!
这个分解就揭示了递归的本质,大家都是同一个函数,干的都是同一件事,不管在函数的哪个位置,都是实现同样的功能,唯一的差别就是传入的参数不一样罢了
继续向下分解
(n-1)! = (n-1) * (n-2)!

1!=1
分解到1后就无法向下分解了,这就得出跳出递归的条件 n==1

int factorial(int n){
	if (n == 1) 
		return 1;//这里就是终止递归的条件
	else 
		return n * factorial(n - 1);//分解阶乘,提出当前的n值,让同一个函数计算n-1的阶乘
}


cout << factorial(4) << endl;

汉诺塔

汉诺塔的具体规则我就不细说了
在这里插入图片描述

我们从最简单的开始,这里说的几号代表的是第几跟柱子最上面的盘子
1个盘子: 直接从1号移到3号(这隐式的表示出递归结束条件)
2个盘子:先从1号移到2号,然后1号移动到3号,最后2号移动到3号
3个盘子:1号移到3号,1号移到2号,3号移到2号,1号移到3号,2号移到1号,2号移到3号,1号移到3号

n个盘子汉诺塔问题分解为下面三个循环过程
1、将除了底下最大的,剩余的n-1块全部移动到过渡2号柱上
2、将底下最大的移动到目标3号柱上
3、将过渡2号柱上的全部移动到目标3号柱上
代码理解:
假定我有一个函数,他的功能就是完成汉诺塔,将所有的盘子完整的从当前号移动到目标号,不论你是多少层,在我看来最多就是2层,最底下的和上面所有,依照上述2层的情况,我应该把最上面一层移动到过渡号柱子,但其实它有很多个盘子,欸,我不是有汉诺塔函数嘛,那我直接调用不就行了,这就对应了

hanoi(n - 1, p1, p3, p2);

然后我把最底下的移动到最终目标号柱子上,对应了

cout << p1 << "号移动到" << p3 << "号" << endl;

上面我已经把最大的移动归位了,那就而当他是空气好了,不管我怎么移动,他都不会影响我,那么最后的目标就是把我放在过渡号柱子上的盘子移动到最终号柱子上,这简单啊,我再调用一次汉诺塔函数不就行了,但这里当前盘子所处的号变了,过渡号也变了。对应了

hanoi(n - 1, p2, p1, p3);

有人会想函数里面两次调用自身的函数,那里面的参数会不会随着反复调用而做出正确改变呢,那当然会!,回到我们定义函数的输入参数
第一个参数是汉诺塔的层数,他每次调用会进行n-1的操作
后面三个参数是当前柱子号,过渡柱子号,当前目标柱子号
他每一次调用都会对应着改变,因为他只有3种号,我们预先输入的从几号到几号,那就会正确执行。
就拿把n-1层从1号移动到3号来说,我们就可以看成这是个n-1层的汉诺塔问题,我的目标不是3号而是2号了,这个目标是几号没有任何区别

// n:n层汉诺塔 p1: 当前所在柱子号 p2: 当前过渡柱子号 p3:当前目标柱子号

void hanoi(int n, int p1, int p2, int p3) {
	if (n == 1)
		//这个是递归结束条件,只剩一个了的时候直接移动就好了
		cout << p1 << "号移动到" << p3 << "号" << endl;
	else {
		/*这对应了上述循环过程的第一个,将n-1个盘子移动到2号柱,
		注意是同一个函数,但是参数已经发生了改变
		输入变成n-1个盘子,当前所在的柱子号没有改变还是p1,
		目标柱子和过渡柱子改变成p2和p3
		*/
		hanoi(n - 1, p1, p3, p2);
		//对应了第二个步骤,将所在p1移动到目标p3
		cout << p1 << "号移动到" << p3 << "号" << endl;
		/*
		对应了第三个步骤,还是那个函数,改变了的是参数
		n-1个,当前所在柱子号为p2,目标依旧是p3,过渡变成p2
		*/
		hanoi(n - 1, p2, p1, p3);
	}
		
}

hanoi(n - 1, p2, p1, p3);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值