入门深度理解递归(一)

什么是递归?递归就是函数对函数自身的反复调用
理论上来讲递归并不是很容易,去理解递归的过程反而比较重要

我们需要有一个分而治之的思想,所谓分而治之就是将一个简单的问题分解成一个简单的问题的集合,比如对于 ab 我们可以将函数分解成 a(b-1) ,将问题逐步分解后可以得到当b=1时函数值为a,这就是分而治之的思想。

首先从两数的乘法来理解函数的递归

1.函数的乘法
 首先看一段代码

#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int a,b,ans;

inline int mul(int a,int b){
	if(b==1){
		return a;
	}
	else{
		return mul(a,b-1)+a;
	}
} 

int main(){
	cin>>a>>b;//输入 scanf("%d%d",&a,&b);
	cout<<mul(a,b);//输出 printf("%d",mul(a,b));
}

可以将两数的乘法视为多个数的加法,比如现在要计算 ab 那么我们可以将计算过程分解为 b 个 a 相乘那么比如
在这里插入图片描述
逐步将数字分解,函数当函数递归到最底层时,函数值返回 a 表示加上了最后的 a 之后将函数逐步加上 a 返回即可,这样逐步递归就能得到a
b的值,最重要的是读懂代码,可以在草稿纸上简单演算一下。

了解了函数递归求乘法之后,我们可以用递归来求斐波那契数列。
2.递归求斐波那契数列
什么是斐波那契数列:1 1 2 3 5 8 13 21 … …
这样的数列,数列的前两项是1,第三项及以后的数字为前两项之和
我们可以将问题转化成求第n-1项和第n-2项的和
那么将问题逐步简化,那么问题的根源就到了n=1和n=2时的情况了

#include<cstdio>
#include<cstring>
using namespace std;

inline int fibo(int n){
	if(n==2 || n==1){
		return 1;
	}
	else {
		return fibo(n-1)+fibo(n-2);
	}
}

int main(){
	int n;
	scanf("%d",&n);
	printf("%d",fibo(n));
}

如下我们就可以求得斐波那契数列指定项的值

3.递归求阶乘
同样,求阶乘就是将n!逐步分解到1,12,12*3 … …
这样逐步分解就可以得到n的阶乘

#include<cstdio>
#include<cstring>
#include<iostream> 
#include<algorithm>
using namespace std;

inline int mul(int n){
	int ans=1;
	if(n==1){
		return ans;
	}
	else{
		return mul(n-1)*n;
	}
}

int main(){
	int n;
	scanf("%d",&n);
	printf("%d",mul(n));
	return 0;
}

4.递归求等差数列
同样的思路逐步将n缩小到等于1的情况
就能输出等差数列

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int a1,d;

inline int ans(int n){
	if(n==1){
		printf("%d ",a1);
		return a1;
	}
	else{
		int a=ans(n-1)+d;
		printf("%d ",a);
		return a;		
	}
}

int main(){
	int n;
	scanf("%d%d%d",&a1,&d,&n);
	ans(n);
	return 0;
} 

这个代码可以输出等差数列的所有项而不局限于所要查询的部分,而如果只需要输出所要查询的项那么只需要将ans函数简单改一下就可以了。

5.递归求汉诺塔
什么是汉诺塔

有三根相邻的柱子,标号为A,B,C,A柱子上从下到上按金字塔状叠放着n个不同大小的圆盘,要把所有盘子一个一个移动到柱子B上,并且每次移动同一根柱子上都不能出现大盘子在小盘子上方

这是一道递归的经典例题
对于有四个盘子的情况来讲
可以看如下动图来表示转移情况
在这里插入图片描述
我们先来递推下情况(假设杆子由左到右)
当只有一个盘子的时候:
在这里插入图片描述
这样一步就可以
1->3

对于两个盘子的情况在这里插入图片描述
可以
1->2
1->3
2->3

对于三个盘子的情况
在这里插入图片描述
可以
1->3
1->2
3->2
1->3
2->1
2->3
1->3
这样的话我们不难发现其实对于n个盘子的转移我们可以视为将n-1个盘子通过2号柱子逐步转移到3号柱子上,目的是将最大的盘子最先转移到目标柱上
这样就实现了递归的条件
需要分两步进行
第一步是将n-1个盘子通过3转移到2上在将最大的转移到3上
第二步时将n-1个盘子通过1转移到3上
这样就实现了结果并且可以输出步骤
程序

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

inline void hanoi(int n,char a,char b,char c){
	if(n==1){
		printf("%c -> %c\n",a,b);
		return;
	}
	else if(n==2){
		printf("%c -> %c\n",a,c);
		printf("%c -> %c\n",a,b);
		printf("%c -> %c\n",c,b);
		return ;
	}
	else{
		hanoi(n-1,a,c,b);
		printf("%c -> %c\n",a,b);
		hanoi(n-1,c,b,a);
	}
}

int main(){
	char a='1',b='3',c='2';
	int n;
	scanf("%d",&n);
	hanoi(n,a,b,c);
	return 0;
} 

一点点小建议
关于递归: 一定不要试图跟踪大型递归的过程!(之后学的BFS,DFS剪枝,树上搜索等等方法,你敢跟踪全部过程要疯掉的) 要写出递归,关键就是找出递归的递归方程式: 也就是说,要完成最后一步,那么最后一步的前一步要做什么。

这篇文章最难的就是汉诺塔问题,当时的我也多次理解汉诺塔然后一段时间后发现又不理解了(当场去世
这个就反复理解趴(

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值