首先需要知道的是:
递归是算法的实现方式,分治是算法的设计思想。
迭代是不断地循环过程,递归是不断地调用自身。
递归
- 直接或间接调用自身的算法。
- 用函数自身给出定义的函数称为递归函数。
- 分治法产生的子问题往往是原问题的较小末世,这就是为使用递归技术提供了方便。原问题与子问题的唯一区别就是输入的规模不同。
递归的弊端就是会不断的消耗内存中的栈空间,并且有相关的值拷贝动作,函数不断压栈,导致资源不断消耗。
分治的过程
- 先将规模变小
- 递归处理小规模问题
- 将小规模问题合并为原始的问题的解
需要注意的是:
- 分解的条件要互斥,
- 分解后所有的条件加在一起,能够覆盖原始问题的所有情况
实例
1.阶乘函数
递归定义:
代码实现:
//阶乘
#include<iostream>
using namespace std;
//递归算法
int factorial_recursive(int n){
if(n==1)return 1;
return n*factorial_recursive(n-1);
}
//一般算法
int factorial_loop(int n){
int res=1;
for(int i=n;i>0;i--){
res*=i;
}
return res;
}
int main(){
int n;
cout<<"输入阶乘的n值:";
cin>>n;
cout<<"使用递归算法:\n";
cout<<n<<"! = "<<factorial_recursive(n)<<endl;
cout<<"使用一般算法:\n";
cout<<n<<"! = "<<factorial_loop(n)<<endl;
return 0;
}
2.斐波那契数列
递归定义:
代码实现:
//斐波那契数列
#include<iostream>
using namespace std;
//递归
int fibonacci_recursive(int n){
if(n==0 || n==1){
return 1;
}
return fibonacci_recursive(n-1)+fibonacci_recursive(n-2);
}
//一般算法
int fibonacci_loop(int n){
if(n==0 || n==1){
return 1;
}
int res1=1;
int res2=1;
int res=0;
for(int i=1;i<n;i++){
res=res1+res2;
res1=res2;
res2=res;
}
return res;
}
int main(){
cout<<"你想要输出多少个斐波那契数列里的值:";
int n;
cin>>n;
//递归算法
cout<<"fibonacci implement by recursive:\n";
for(int i=0;i<n;i++){
cout<<fibonacci_recursive(i)<<" ";
}
cout<<endl;
//一般算法
cout<<"fibonacci implement by loop:\n";
for(int i=0;i<n;i++){
cout<<fibonacci_loop(i)<<" ";
}
cout<<endl;
}
3.Ackerman函数
当一个函数及它的一个变量是由函数自身定义时,称这个函数是双递归函数:
递归定义:
代码:
#include <iostream>
using namespace std;
long ackerman(long n, long m){
if (n == 1 && m == 0)
return (long)2;
if (n == 0 && m >= 0)
return 1;
if (m == 0 && n >= 2)
return n + 2;
if (n >= 1 && m>= 1)
return ackerman( ackerman(n-1,m) , m-1);
}
int main()
{
cout << "m = 0 : " << endl;
cout << "ackerman(1,0) = " << ackerman(1,0) << endl;
cout << "ackerman(2,0) = " << ackerman(2,0) << endl;
cout << "ackerman(3,0) = " << ackerman(3,0) << endl;
cout << "ackerman(4,0) = " << ackerman(4,0) << endl;
cout << "m = 1 : " << endl;
cout << "ackerman(1,1) = " << ackerman(1,1) << endl;
cout << "ackerman(2,1) = " << ackerman(2,1) << endl;
cout << "ackerman(3,1) = " << ackerman(3,1) << endl;
cout << "ackerman(4,1) = " << ackerman(4,1) << endl;
cout << "m = 2 : " << endl;
cout << "ackerman(1,2) = " << ackerman(1,2) << endl;
cout << "ackerman(2,2) = " << ackerman(2,2) << endl;
cout << "ackerman(3,2) = " << ackerman(3,2) << endl;
cout << "ackerman(4,2) = " << ackerman(4,2) << endl;
cout << "m = 3 : " << endl;
cout << "ackerman(1,3) = " << ackerman(1,3) << endl;
cout << "ackerman(2,3) = " << ackerman(2,3) << endl;
cout << "ackerman(3,3) = " << ackerman(3,3) << endl;
cout << "ackerman(4,3) = " << ackerman(4,3) << endl;
return 0;
}
4.排列问题
将数列全排列:
n=1时:只有一种排列;
n>1时:将
#include<iostream>
using namespace std;
void perm_recursion(int list[],int k,int m){
if(k==m){
for(int i=0;i<=m;i++)
cout<<list[i]<<" ";
cout<<endl;
}
else{
for(int i=k;i<=m;i++){
swap(list[k],list[i]);
perm_recursion(list,k+1,m);
swap(list[k],list[i]);
}
}
}
int main(){
int list[]={0,1,2};
cout<<"permutation implement by recursion:"<<endl;
perm_recursion(list,0,2);
cout<<endl;
return 0;
}
5.整数划分问题
将正整数n表示为一系列正整数的和。不同的划分个数称为n的划分数,记作p(n),
在正整数n的所有不同划分中,将最大加数n1不大于m的划分个数记作q(n,m)。
正整数n的划分数p(n) = q(n,n)
代码实现:
#include<iostream>
using namespace std;
int q(int n ,int m){
if(n<1||m<1)
return 0;
if(n==1||m==1)
return 1;
if(n<m)
return q(n,n);
if(n==m)
return 1+q(n,m-1);
return q(n,m-1)+q(n-m,m);
}
int p(int n){
return q(n,n);
}
int main(){
for(int i=1;i<7;i++){
cout<<"interger_partition("
<<i<<") ="<<p(i)<<endl;
}
return 0;
}
6.汉诺塔问题
hanoi(n, a, b, c)表示按照游戏规则,n块圆盘从a塔移至b塔,c塔作为辅助塔。
move(a, b)表示将塔a最上面的圆盘移至塔b,并输出这一步骤。
代码实现: