设有一个未知函数f,用其自身构成的已知函数g来定义:
f(n)=g(n,f(n-1)) n>0
f(0)=a n=0
为了定义f(n)必须f(n-1)……用自身的简单情况来定义自己的方式称为递归定义
一个递归定义必须是有确切含义的,也就是说,必须一步比一步简单,最后是有终结的,决不能无限循环下去。在f(n)的定义中,当n为0时定义一个已知数a,是最简单的情况,称为递归边界,它本身不再使用递归的定义。
与递推一样,每一个递归定义都有其边界条件。但不同的是,递推是由边界条件出发,通过递推式求f(n)的值,从边界到求解的全过程十分清楚;而递归则是从函数自身出发来达到边界条件。在通往边界条件的递归调用过程中,系统用堆栈把每次调用的中间结果(局部变量和返回地址值)保存起来,直至求出递归边界值f(0)=a。然后返回调用函数。返回过程中,中间结果相继出栈恢复,f(1)=g(1,a)-》f(2)=g(2,f(1))直至求出f(n)=g(n,f(n-1))
递归算法的效率往往很低,费时和费内存空间。但是递归也有其长处,它能使一个蕴含递归关系且结构复杂的程序简洁精炼,增加可读性。特别是在难于找到从边界到解得全过程的情况下,如果把问题推进一步,其结果仍维持原问题的关系,则采用递归算法编程比较合适。
递归按其调用方式分
(1)直接递归——递归过程P直接自己调用自己
(2)间接递归——即P包含另一过程D,而D又调用P
1
递归算法适用的一般场合为:
(1)数据的定义形式按递归定义(斐波那契数列)
(2)数据之间的关系(即数据结构)按递归定义。(树的遍历,图的搜索)
(3)问题解法按递归算法实现。(回溯法)
(2)、(3)可利用堆栈结构将其转换为非递归算法
例题1是属于计数类型,即计算具有某种特性的对象有多少;
/*
* =====================================================================================
*
* Filename: divide.cc
*
* Description: 具体划分介绍看上面解释
*
* Version: 1.0
* Created: 2015年05月09日 10时44分16秒
* Revision: none
* Compiler: gcc
*
* Author: xiu,
* Organization:
*
* =====================================================================================
*/
#include<iostream>
using namespace std;
/*
#define N 4
const int S[N] = { 1, 2, 3, 4 };
const int K = 3;
*/
#define N 5
const int S[N] = { 1, 2, 3, 4, 5 };
const int K = 3;
int divide(int n, int k)
{
if (n < k || (k == 0 && k < n))
{
return 0;
}
if (k == 1 || k == n)
{
return 1;
}
if(n > k && k >=1 )
{
int data = divide(n - 1, k - 1) + k * divide(n - 1, k);
return data;
}
}
int main()
{
int temp = divide(N, K);
cout << temp << endl;
return 0;
}