递归法的应用:求解斐波那契数列和数字的组合问题
- 递归:是指函数、过程、子程序在运行过程中直接或间接调用自身而产生的重入现象。采用递归编写程序能是程序变的见解和清晰。
- 递归的用法一般为:
- 定义是递归的:有许多数学公式、树、数列等的定义是递归的。
- 数据结构是递归的:单链表就是一种递归的数据结构。
- 问题的求解方法是递归的:有些问题的求解方法是递归的,典型的有Hanoi塔问题求解。
- 但递归也有缺点,该算法解题的运算效率低,在递归调用过程中系统为每一层的返回值、局部变量等开辟了栈空间来存储,递归次数过多容易造成栈溢出。
- 能采用递归描述的算法通常有这样的特征:为求解规模为N的问题,设法将其分解为规模较小的问题,然后从这些小问题的解方便的结构造出大问题的解,并且这些规模较小的问题也采用同样的分解和综和方法分解成规模更小的问题,并且这些更小问题的解构造出规模较大问题的解。它包括递归出口和递归体两部分,前者确定何时结束递归,后者确定递归求解的递推关系。
题目1:编写计算fibonacci数列的第n项函数fib(n)。
- 首先来看一下循环的版本:
int fib(int n)
{
int result[3] = {0, 1, 1};
if(n <= 2)
{
return result[n];
}
int fibfirst = 0;
int fibsecond = 1;
int fibn = 0;
while(n > 1)
{
fibn = fibfirst + finsecond;
fibnfirst = fibsecond;
finsecond = fibn;
n--;
}
return fibn;
}
- 递归版本
int fibn(int n)
{
if(n == 0)
return 0;
if(n == 1)
return 1;
if(n > 1)
return fibn(n - 1) + fibn(n - 2);
}
- 从这两个例子我们看见了递归的魅力,他把复杂问题的求解分解为简单的小问题来分别求解,在根据简单小问题的解来构造复杂问题的解。这使得代码看起来清晰,简单。
题目2:数字组合问题。找出自然数1,2,3,. . . . . .,n。中任取 r 个数的所有组合(r <= n)。
- 解法描述:当组合的第一个数选定时其后的数字是从余下的n-1个数字中选取r-1个数的组合,这样将求n个数中r个数的组合转化为求n-1个数中r-1个数的组合问题。在函数中使用一个工作数组来存放求出组合的数字,约定函数将确定的r个数字组合的第一个数字存放在arr[r]中,当第一个组合求出后,才将arr[]中的一个组合输出,第一个数可以是n,n-1,…,r,函数将确定组合的第一个数字放入数组后,有两种可能的选择,因还未去掉组合的其余元素,继续递归确定;或者已经确定了组合的全部元素,输出这个组合。
#include<iostream>
using namespace std;
int arr[100];
void com(int n, int r)
{
int i = 0, j = 0;
for(i = n; i >= r; i--)
{
arr[r] = i;
if(r == 1)
{
for(j = 1; arr[j] > 0; j++)
{
cout << arr[j] << " ";
}
cout << endl;
continue;
}
com(i - 1, r - 1);
}
}
int main()
{
int i = 0;
for(i; i < 100; i++)
{
arr[i] = 0;
}
int n, r;
cin >> n >> r;
com(n, r);
return 0;
}
测试结果如下图: