第2章 递归与分治策略
2.1 递归算法
递归算法:直接或间接地调用自身的算法。
递归函数:用函数自身给出定义的函数。两个要素:边界条件、递归方程
优点:结构清晰,可读性强,而且容易用数学归纳法来证明算法的正确性。
缺点:运行效率较低,无论是耗费的计算时间还是占用的存储空间都比非递归算法要多。
解决方法:在递归算法中消除递归调用,使其转化为非递归算法。
1、采用一个用户定义的栈来模拟系统的递归调用工作栈。该方法通用性强,但本质上还是递归,只不过人工做了本来由编译器做的事情,优化效果不明显。
2、用递推来实现递归函数。
3、通过变换能将一些递归转化为尾递归,从而迭代求出结果。
后两种方法在时空复杂度上均有较大改善,但其适用范围有限。
例1.阶乘函数
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<stdlib.h>
#include<algorithm>
using namespace std;
long long factorial(long long n)
{
if(n==0) return 1;
else return n*factorial(n-1);
}
int main()
{
long long n;
long long result;
cout<<"this app compute the factorial of n,please input n:"<<endl;
while(cin>>n)
{
result=factorial(n);
cout<<"The factorial of "<<n<<" is: "<<result<<endl;
}
return 0;
}
例2. Fibonacci数列
无穷数列1,1,2,3,5,8,13,21,34,55,……,称为Fibonacci数列。它可以递归地定义为:
代码:
#include<iostream>
#include<stdlib.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int Fibonacci(int n)
{
if(n==0||n==1) return 1;
else return Fibonacci(n-1)+Fibonacci(n-2);
}
int main()
{
int n,result;
cout<<"this app compute Fibonacci of n, please input n:"<<endl;
while(cin>>n)
{
result=Fibonacci(n);
cout<<"the Fibonacci of "<<n<<" is :"<<result<<endl;
}
return 0;
}
例3 .Ackerman函数
当一个函数及它的一个变量是由函数自身定义时,称这个函数是双递归函数。
Ackerman函数A(n,m)定义如下:
代码:
#include<iostream>
#include<stdlib.h>
#include<math.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int Ackerman(int n,int m)
{
if(n==1&&m==0) return 2;
else if(n==0&&m>=0) return 1;
else if(n>=2&&m==0) return n+2;
else if(n>=1&&m>=1) return Ackerman(Ackerman(n-1,m),m-1);
}
int main()
{
int n,m,result;
cout<<"this app compute the problem of Ackerman,please input n and m:"<<endl;
while(cin>>n>>m)
{
result=Ackerman(n,m);
cout<<"the result is :"<<result<<endl;
}
return 0;
}
例4.全排列问题:123 -> 123 132 213 231 312 321</