递归法

递归法(Recursion)是一种在函数或方法中调用自身的编程技术,在计算机方法中,使用递归技术往往使函数的定义和算法的描述简洁且易于理解。任何可以用计算机求解的问题所需要的计算时间都与其规模有关。而且规模越小,解题所需要的计算时间通常越小,从而比较容易处理。

简而言之,递归思想就是用与自身问题相似但规模较小的问题来描述自己。

例如,兔子出生两个月后就有繁殖能力,一对兔子每个月能生出一对兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?

第一个月小兔子没有繁殖能力,所有还是一对;两个月后,生下一对,兔子共2对;三个月后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对。

以此类推,如下所示。

所经过月数:0 1 2 3 4 5  6   7   8   9  10   11  12

兔子对数:   1  1 2 3 5 8 13 21 34 55 89 144 233

表中数字1,1,2,3,5,8^233构成一个序列。这个数列有个明显的特点,即前面两项之和构成后一项。用数学表示这个无穷数列称为裴波那契数列,形式化描述为:

     1          , n=0

F(n)=  1       ,n=1

    F(n-1)+F(n-2)  ,n>1

该数列就是个典型递归数列。

#include<iostream>
using namespace std;

int fib(int n) {
    int f=0;
    if(n==1)    return 0;
    if(n==2)    return 1;
    f=fib(n-1)+fib(n-2);
    return f;
}

int main() {
    int n,i,m=0;
    cin>>n;
    m=fib(n);
    cout<<"第"<<n<<"项是"<<m<<endl;
    m=0;
    for(i=1;i<=n;i++)
        m=fib(i)+m;
    cout<<"前"<<n<<" 项和是"<<m<<endl;
    return 0;
}

递归算法的特性:

(1)求解规模为n的问题可以转换成一个或多个结果相同、规模较小的问题,然后从这些小问题的解能方便地构造出大问题的解。

(2)递归调用的次数必须是有限的。

(3)必须有结束递归的条件(边界条件)来终止递归。即当规模为1时,能够直接得解。

递归的执行过程:

递归算法的执行过程划分为递推和回归两个阶段。在递推阶段,把规模为n的问题求解推到比原问题的规模较小的问题求解,且必须要有终止递推的情况。在回归阶段,当获得最简单情况的解后,逐渐返回,依次得到规模较大问题的解。

需要注意的是,用递归描述问题并不表示程序也一定要直接用递归实现。

递归算法的优点:结构清晰、可读性强,而且容易用数学归纳法来证明算法的正确性,因此它为设计算法、调试程序带来很大方便。

递归算法的缺点:运行效率相对较低,无论是耗费的计算时间还是占用的存储空间都比非递归算法要多。通常解决方法是消除递归算法中的递归调用,使递归算法转换为非递归算法。

理论上递归算法都可以转换为非递归算法。方法有如下3种

(1)通过分析,跳过分解部分,直接用循环结构实现求值过程。

(2)用栈保存程序的运行过程,通过分析只保存必须保存的信息,从而用非递归算法替代递归算法。

(3)利用栈保存参数,由于栈的后进先出特性与递归算法的执行过程相似,因而可以用非递归算法替代递归算法。

1汉诺塔问题求解

假设有n个金盘,并且金盘由小到大一次编号为1,2,3……n。要把放在A针上的n个金盘移到目的针C上。当只有一个金盘,即n=1时,只要将编号为1的金盘从A针直接移到C针上即可。当n>1时,可以把最上面的n-1个金盘看作一个整体。这样n个金盘就分成了两个部分:上面n-1个金盘和最下面的编号为n的金盘。移动金盘的问题可以转换为如下3个步骤:

1)借助C针,将n-1个金盘从A针移到B针上;

2)将编号为n的金盘直接从A针移到C针上;

3)借助A针,将B针上的n-1个金盘移到C针上。

其中,第二步只移动一个金盘,容易解决。第一、三步不能直接解决,但由于已经把移到n个金盘问题变成了移到n-1个金盘的问题,问题规模变小。如果再把第一、三步分别变成类似的三个子问题,移到n-1个金盘的问题就可以变成移到n-2个金盘的问题,依次类推,从而将问题加以解决。

#include<iostream>
using namespace std;

void Move(int n,char x,char y) {
    cout<<"把"<<n<<" 号从 "<<x<<"挪动到 "<<y<<endl;
}

void Hannoi(int n,char a,char b,char c) {
    if(n==1)
        Move(1,a,c);
    else {
        Hannoi(n-1,a,c,b);
        Move(n,a,c);
        Hannoi(n-1,b,a,c);
    }
}

int main() {
    cout<<"以下是3层汉诺塔的解法"<<endl;
    Hannoi(3,‘a‘,‘b‘,‘c‘);
    cout<<"输出完毕!"<<endl;
    return 0;
}

2 八皇后问题

在8*8国际象棋盘上放置8个黄昏,使任何一个皇后都不能吃掉另一个。即任意两个皇后都不能处于同一行、同一列或者同一斜线上,问共有多少种放置方案。

假设当前生成全排列中的第t个数字大于n,其中,t是每一行从左到右的标号,n是棋盘的行数,则说明生成了一个全排列,否则:

1)从1~8中依次取出一个数字来尝试,如果此数字前面已经出现,则取下一个数字,直到找到第一个没有出现过的数字;

2)将这个数字标记为已出现,然后以同样的方法生成全排列中的下一个数字;

3)将这个数字标记为未出现;

显然,这是一个递归定义,递归的结束条件为t>n。

#include<iostream>
using namespace std;
int result=1;
int chess[8];

//根据前面几行的棋子,检查这一行所放的棋子是否合法
int check(int n) {
    int i;
    for(i=1;i<=n-1;i++) {
        if(chess[n] == chess[i]+(n-i) || chess[n]==chess[i]-(n-i) || chess[n]==chess[i])
            return 0;
    }
    return 1;
} 

 void show_chess(void) {
     int i;
     cout<<endl<<"Result -"<<result<<endl;
     for(i=1;i<=8;i++) {
         cout<<i<<" : "<<chess[i]<<"\t";
     }
     ++result;
 }

 //递归函数:放棋子
void putchess(int n) {
    int i;
    if(n<=8) {
        for(i=1;i<=8;i++) {//将第n行从第一格(i)开始往下放
            chess[n]=i;
            if(check(n) == 1) {//若可放,则检查是否放满
                if(n==8)
                    show_chess();//若已放满到8行时,则表示找出一种解,打印出来
                else
                    putchess(n+1);//若没放满则放下一行 putchess(n+1)
            }
        }
    }
} 

int main() {
    cout<<"This is for 8*8 matrix"<<endl;
    putchess(1);
    return 0;
}
时间: 2024-07-31 22:04:52

递归法的相关文章

谭浩强 c程序设计 8.17用递归法将一个整数n转换成字符串。例如,输入486,应输出字符串&quot;486&quot;。n的位数不确定,可以是任意位数的整数。

8.17用递归法将一个整数n转换成字符串.例如,输入486,应输出字符串"486".n的位数不确定,可以是任意位数的整数. #include <stdio.h> char str1[20];int i=0;long n;int main(){        int longToStr(long n);    char *revstr(char *str, int len);    printf("请输入一个整数n:\n");    scanf("

2.简单求和[递归法]

计算1+2+3+4+5,用递归法的两种形式,练习这题主要查看递归规律,训练递归,形成递归的[本能].第一种,从后往前加. int sum(int a[],int n) { return n==0?0:sum(a,n-1)+a[n-1]; } 第二种,从两边对加,例:(1+5)+(2+4)+3,这个需要判定,假如数组的个数为偶,则左边+1==右边,如果为奇数,则左边+2==右边,需要将这三个数之和返回: int sum(int a[],int l,int r) { if(l+2==r)/*中间隔一

C语言之函数调用13—递归法求N阶勒让德多项式的值

//递归法! /* ======================================================= n阶勒让德多项式,n=1时,Pn(x)=x;n>=1时, Pn(x)=((2n-1)x-Pn-1(x)-(n-1)Pn-2(x))/2. ======================================================= */ #include <stdio.h> #include <math.h> double p(

C语言之函数调用14—递归法打印勒让德多项式前N项

//递归法 /* ================================================================== 题目:勒让德多项式 ================================================================== */ #include <stdio.h> double p(int n,double x) { if(n==0)return 1.0; else if(n==1)return x; else

C语言之函数调用16—递归法之一般函数的调用

//递归法 /* ================================================================== 题目:F(x,1)=1 F(x,n)=F(2x+1,n-1)*x  (n>1) ================================================================== */ #include<stdio.h> double F(float x,int n) { if(n==1) return

循环赛日程表(递归法)

#include<iostream> #include<vector> #include<iterator> #include<algorithm> using namespace std; /* *循环赛日程表(递归法) */ void Copy(int **map,int sr,int sl,int dr,int dl,int k) { for (int i = 0; i < k; i++) { for (int j = 0; j < k;

用递归法计算斐波那契数列的第n项

   斐波纳契数列(Fibonacci Sequence)又称黄金分割数列,指的是这样一个数列:1.1.2.3.5.8.13.21.--在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)在现代物理.准晶体结构.化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1960年代起出版了<斐波纳契数列>季刊,专门刊载这方面的研究成果. [Fibonacci.cpp] #include<iostream>#

算法笔记_013:汉诺塔问题(Java递归法和非递归法)

目录 1 问题描述 2 解决方案  2.1 递归法 2.2 非递归法 1 问题描述 Simulate the movement of the Towers of Hanoi Puzzle; Bonus is possible for using animation. e.g. if n = 2 ; A→B ; A→C ; B→C; if n = 3; A→C ; A→B ; C→B ; A→C ; B→A ; B→C ; A→C; 翻译:模拟汉诺塔问题的移动规则:获得奖励的移动方法还是有可能的.

C语言之函数调用17—递归法之一般函数的调用(2)

//递归法 /* ================================================================== 题目:求F(60),其中F(n)定义如下: F(0)=0; F(1)=1; F(2n)=f(n)+3; F(2n+1)=F(n)+F(2n-1). ================================================================== */ #include<stdio.h> double F(in

八皇后问题,递归法实现

八皇后问题,是19世纪著名的数学家高斯在1850年提出的:在8×8格的国际象棋盘上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列.同一斜线上,试问有多少种摆法?高斯先生给出的答案是“76”种,实际是76种吗? 八皇后问题是回溯算法的典型应用,但是本文提供递归的求法. 递归的核心思想可以总结成:把一个复杂的问题无限缩小,每个小问题的解法都是一样的,最终归结于求解每个小问题的原型.递归编程的思路可以假设所有的问题都已解决,来到结束条件,这是非常简单的,然后再调用自身求解整个问