从0开始学习递归

递归算是算法中比较大的一道坎,时常因为想观察内部过程而百思不得其解。
在此记录一下本人学习递归的心得,我会用递归去实现简单到复杂的题目。
首先,构造递归方程的特点:
1. 首先 需要知道递归的出口,也就是递归函数结束的条件;
2. 观察递归关系式,如果问题的解决方式都一样的话,那么大的问题就可以划分为小问题。小问题会到达递归出口,再次返回给大问题;
3. 建立递归方程
以下问题 均使用以上步骤解决

问题1 ,数组求和,已知一个数组array[ ],用递归的方法求sum( array );
1.递归出口:如果数组只有一个元素 sum( array[ ] ) = array[ 0 ];
2.递归关系:拆解为子问题,观察sum(array[ n ])与sum(array[ n-1 ])的关系,如果没有,多观察几项或者从整体观察;
3.建立递归方程:sum( array[ n ] ) = sum( array[ n - 1 ] ) + array[ n ];

int sum(int array[], int n){
	if(n==0) return array[0];
	else{
		return (sum(array, n-1) + array[n]);
	}
}

int main(){
	int a[10]={1,2,3,4,5,6,7,8,9,0};
	cout<<sum(a,9);
	return 0;
}
out: 45

问题2 , 求数组中的最大值,已知一个数组array[ n ],求Max(array[ n ]);

  1. 递归出口:如果只有一个元素,最大值就是array[ 0 ];
  2. 递归关系:本例在数值上没有规律,但是可以从局部观察到整体:
  3. 如果n1;Max(array[ n ]) = array[ 0 ];
    如果n
    2;Max(array[ n ]) = max(array[ 1 ] array[ 0 ]);
    如果n3;Max(array[ n ]) = max(array[ 2 ], array[ 1 ], array[ 0 ]);
    此时我们发现 Max(array[ 2 ])已经有了结果;那第三步又可以化简如下
    如果n
    3;Max(array[ n ]) = max(Max(array[ 1 ]), array[ 0 ]);
    类推n==4;Max(array[ n ]) = max(Max(array[ 2 ]), array[ 3 ]);
    最终我们得到递归方程 Max(array[n]) = max(Max(array[n-2]), array[n-1]);
int GetMax(int array[], int n){
	if (n == 0) return array[0]; 
	else{
		return GetMax(array, n-1) > array[n] ? GetMax(array,n-1) : array[n];
	} 
}

int main(){
	int array[7] = {2,33,54,65,21,61,1};
	int max = array[6];
	cout << GetMax(array, 6);
	return 0;
}
out: 65

我们熟悉的 Fibnacci 数列
1.出口 f( 1 ) = f( 2 ) = 1;
2.递归关系 第 n 项是 n -1 项 + n - 2 项
3. 递归方程 f( n ) = f( n - 1 ) + f( n - 2 );

int fibnacci(int n){
	if(n == 1 || n == 2) return 1;
	else return (fibnacci( n - 1 ) + fibnacci( n - 2 ));
}
int main(){
	int n;
	cin>>n; 
	cout<<fibnacci(n);
	return 0;
}

以上是一维数组,二维数组同理。
如果我们想要用递归的方法打印出杨辉三角,同样按照规律

  1. 递归出口:如果只有一层的话,a[0][0] = 1 && i < j ;
  2. 递归关系:如果超过一层的话,每一项的值 a[i][j] 都等于 a[i-1][j-1] + a[i][j-1]
  3. 因此可以列出递归关系式 a[i][j] = a[i-1][j-1] + a[i][j-1]
    在这里插入图片描述
int Function(int i, int j){
	if (i < j) return 0;
	if (i==0 || j==0) return 1; 
	else{
		return (Function(i-1,j-1) + Function(i-1,j));
	} 
}

int main(){
	cout<<Function(4,2)<<endl;
}
out : 6
Function(9,4) : 126

最后举一个经典的汉诺塔例子吧:
在这里插入图片描述

  1. 递归出口:当有一个盘子时,我们将直接由A —> C
  2. 递归关系:当有n个盘子时,我们先将前 n - 1 个盘由 A —> B 再将第 n 个盘由 A --> C 再将前 n - 1 个盘由 B–> C
    为了更方便的观察
    当有1个盘子时,A —> C;
    当有2个盘子时,A —> B, A---->C , B---->C;
    当有3个盘子时,A —> C, A---->B , C---->B, A—>C, B—>A, B—>C, A—>C;

需要注意的是 加粗的 A–>C 是将中间的第 2个盘由 A --> C ;
前面的部分A —> C, A---->B , C---->B是 将前 1 个盘由 A —> B。
后面的部分 B—>A, B—>C, A—>C是 将前 1 个盘由 B–> C
在此 我们观察前一部分 A —> C, A---->B , C---->B ,跟当有2个盘子时的 A —> B, A---->C , B---->C;我们不难发现,只是BC调换了位置。同理 我们观察‘’B—>A, B—>C, A—>C ” 与 “A —> B, A---->C , B---->C” 发现,这时是AB调换了位置。

当有4个盘子时,A–>B, A–>C, B–>C, A–>B, C–>A, C–>B, A–>B, A–>C, B–>C, B–>A, C–>A, B–>C, A–>B, A–>C, B–>C;
我们用前一部分与三个盘子比较A —> C, A---->B , C---->B, A—>C, B—>A, B—>C, A—>C 还是BC调换了位置,同理,后一部分是相同的。因此我们可以写出递归的方程

  1. 第n个盘子移动是在第n-1个盘子移动的基础上调换了BC顺序,移动第n个盘子之后,然后在第n-1个盘子基础上移动AB顺序;
    hanoi(n - 1, a, c, b);
    hanoi(1, a, b, c);
    hanoi(n - 1, b, a, c);
#include <iostream>
#include <algorithm>
using namespace std;
int t, n;
void hanoi(int n, char a, char b, char c)
{
	if (n == 1)
		cout << "第" << ++t << "步:" << a << "-->" << c << endl;
	else
	{
		hanoi(n - 1, a, c, b);
		hanoi(1, a, b, c);
		hanoi(n - 1, b, a, c);
	}
}
int main()
{
	cin >> n;
	char a = 'A', b = 'B', c = 'C';
	hanoi(n, a, b, c);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lins H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值