递归算法,斐波那契 和 汉诺塔

为了解决一些复杂的问题,需要使用递归策略。而递归在现实中很难找到直接的对应关系。

递归并不是一个在日常生活中出现的概念,所以使用递归会有点难,但是递归有时候真的很强大,完全值得花时间学习。

递归的定义是,将一个大问题分解成具有相同形式的小问题,相同形式是关键。子问题与初始问题的差别仅仅是范围上的不同。
将子问题分解成更小的子问题,直到这些问题达到足够简单,能够被立即解决的水平,才停止继续分解。 因为这样递归也被称为“分而治之策略”。
有一个调用自身的函数,是递归的决定性特征
递归函数

符合以下条件可以使用递归:
1,必须能够鉴别出一个简单的情景,且该情景的答案是容易确定的。
2,必须能够确认一个递归的分解方式,能够将问题的复杂实例分解为更小的、具有相同形式的问题。

可以先写“阶乘函数”和“斐波那契函数”来理解递归,因为数学中的这两个函数能很直观的看出递归。
从程序员的观点来看,数学定义的实践意义在于它为递归的实现提供了一个模板。

下面简单说一下斐波那契函数
斐波那契序列

像 “斐波那契序列” 这种类型的表达式,序列的每一个元素都由先前的元素来决定,这种序列就称为递归关系。
只靠递归关系是不能写出 斐波那契函数的,虽然使用上图中的那个公式可以计算出新项 t(n) 的值,但这个过程必须有个起点(这个起点其实也就是递归函数里面的终止条件)。为了使用上图那个公式需要数列的头两项。 t(0) 和 t(1),斐波那契的完整定义如下:

斐波那契定义
下面是斐波那契代码

#include <iostream>
using namespace std;
int fib(int n) {
	if (n < 2)
		return(n);
	else
		return(fib(n - 1) + fib(n - 2));
}
int main()
{
	int i;
	cout << "斐波那契数列 0到12 :" << endl;
	for (i = 0; i <= 12; i++) {
		cout << "fib:" << i;
		cout << " = "<< fib(i) << endl;
	}
}

对于很多人来说递归不是一个容易掌握的概念。有效使用递归需要大量练习,以一种全新的方式来解决问题。 关键在于学习递归的思考方式。

为什么理解递归时会头脑混乱? 因为我们刚开始学编程时会通过理解逐个细节部分来理解程序整体。然而,学习递归时,递归思维要求考虑整体。在递归领域中部分是理解的敌人,会妨碍理解递归。 所以要有对递归的跳跃信任。

递归函数都开始于if,如果不是,那怕是要去检查你的设计是否可行。

递归是有去有回的,递归函数每次调用自己都会创建一个新的栈帧,直到满足函数中的if条件,这时开始逐步从小往上消栈。递归的执行过程都是这样。

下面说汉诺塔:
在这里插入图片描述
起初有8个圆盘在塔座A上,目标是把A塔座上的8个盘移到B塔座上,规则是每次只能移动一个盘,在移动过程中,始终保持大盘在下。

分解问题:
把递归用到汉诺塔这问题上,必须首先考虑这问题更普通的情况,尽管最终目标是把8个圆盘从A移到B。这个问题的递归分解包含在不同形状下把更少的圆盘在塔座间移动。在更普通的情况下,利用第三个塔座作为临时存放处,把一座塔的圆盘移到另外一座。为了确保所有细分的问题符合最初的形式,递归程序需要有以下几个变量:
1,需要移到的圆盘数量
2,最开始圆盘所在的塔座编号
3,最终圆盘所在的塔座编号
4,用做临时存放圆盘的塔座编号

先假设塔上只有3个圆盘,只有3个盘的时候应该要怎么移动,如图:
在这里插入图片描述
可以看到圆盘的移动逻辑并不难。
然后结合着汉诺塔的代码一起看,代码如下

void moveSingleDisk(char a, char b) {
	printf("%c -> %c\n", a, b);
}
void moveTower(int n, char a, char b, char c) {

	if (n == 1)
		moveSingleDisk(a, b);
	else {
		moveTower(n - 1, a, c, b);
		moveSingleDisk(a, b);
		moveTower(n - 1, c, b, a);
	}
}
int main()
{
	moveTower(8, 'A', 'B', 'C');
}

可以用vs2019调试函数moveTower,看清楚代码的执行逻辑,vs可以看到堆栈,其它的IDE不知道。
在这里插入图片描述
递归函数的习惯是先写终止条件,然后再写递归条件。然而在遇到问题要用递归来解决时,递归条件是比较难分解写出来的。
递归就是有去有回嘛,递:就是把大问题分解成最小子问题,归:就是分解到最小问题后,要解决问题的步骤方法。

递归这东西不好掌握,只能不断重复练习,只看文章是绝对掌握不了递归的,要多做题。可以去知乎看看那些讲递归的,很不错。在俺脑子里感觉递归就像一个立体螺旋图,像根弹簧。

递归蕴含的思想有数学归纳法,像多米诺骨牌。

引用知乎的一个例子:
一个小朋友坐在第10排,他的作业本被小组长扔到了第1排,小朋友要拿回他的作业本,可以怎么办?他可以拍拍第9排小朋友,说“帮我拿第1排的本子”,而第9排的小朋友可以拍拍第8排小朋友,说“帮我拿第1排的本子”…如此下去,消息终于传到了第1排小朋友那里,于是他把本子递给第2排,第2排又递给第3排…终于,本子到手啦!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值