【算法】递归(recursion)+经典例题个人分析

来源:互联网 发布:泗阳网络问政12345 编辑:程序博客网 时间:2024/06/05 16:28


定义(个人理解)


1.自己调用比自己小一个规模的自己

2.有结束条件。

3.对问题的细化


ps: 大家可以通过这个效应感性的感受一下递归。

德罗斯特效应:



************************************************************************************************************************************************


递归条件

当然并不是所有的问题都能够用递归来实现。能够实现递归,需要满足以下条件:

1.有递归公式。问题能够分解为一个一个于自身类似的小问题。
2.确切的边。能够最后分解为一个有确定解的问题。

辅助分析图:


个人觉得,这个图应该是能够比较清晰地反映递归的调用了。
我们可以把递归调用看作是在原本的f()函数中又添加了f()函数的代码,只是现在的参数与原来不同罢了。只有当到达边界的时候,函数才会一层一层的被返回。也就是一个一个的问题被完成返回后,最外层的函数才会真正被完成也返回。



不太懂?没关系,咱们从实例中去理解递归~
************************************************************************************************************************************************

经典例题(个人分析)

该排版由易到难,请各位看客根据自己的需求翻阅。

阶乘


问题描述:请输入一个n值,输出n!的值。

code:


运行结果:


变式1:完成Fibonacci数列
变式2:完成Ackerman函数
(答案在最后~)

是不是觉得递归很简单呢?下面咱们再继续吧~


****************************************************************************************************************

汉诺塔问题


问题描述:假设有3个分别命名为X、Y和Z的塔座,在塔座X上插有n个直径大小各不相同、按从小到大编号为1,2,...,n的圆盘(如图所示)。现要求将X轴上的n个圆盘移至塔座Z上并仍按同样顺序叠排,圆盘移动时必须遵循下列规则:
(1)每次只能移动一个圆盘;
(2)圆盘可以插在X、Y和Z中的任一塔座上;
(3)任何时刻都不能讲一个较大的圆盘压在较小的圆盘之上。
请问如何移?要移多少次?

code:


运行结果:


如果感觉有点晕的话也可以:
1.采取最开始解释的方法去看,就是在原来最开始的函数中添加了代码。
2.带入实际数据进去跟着程序运行一遍。
3.看下面动图~
    


汉诺塔栈方法解决:http://www.cricode.com/304.html
****************************************************************************************************************

八皇后问题


问题描述:经典的八皇后问题,即在一个8*8的棋盘上放8个皇后,使得这8个皇后无法互相攻击( 任意2个皇后不能处于同一行,同一列或是对角线上),输出所有可能的摆放情况。

code:


#include <iostream>using namespace std;int c[20],n=8,cnt=0;void print(){ //打印    for(int i=0;i<n;++i){        for(int j=0;j<n;++j){            if(j==c[i])cout<<"1 ";            else cout<<"0 ";        }        cout<<endl;    }    cout<<endl;}void search(int r){    if(r==n){ //当已经排到最后一个皇后的时候位置一定固定。【条件2】        print();        ++cnt;        return;    }    for(int i=0;i<n;++i){ //r表示第几行        c[r]=i; //c[r]=i,表示第r行第i列        int ok=1;        for(int j=0;j<r;++j)            if(c[r]==c[j]||r-j==c[r]-c[j]||r-j==c[j]-c[r]){ //判断是否在同一列,是否在主对角线或副对角线上【条件1】                ok=0;                break;            }        if(ok)search(r+1); //r+1必定不在同一行,故不用判断是否在一行    }}int main(){    search(0);    cout<<cnt<<endl;    return 0;}

运行结果部分截屏:



****************************************************************************************************************
Answer:
变式1:使用公式f[n]=f[n-1]+f[n-2],依次递归计算,递归结束条件是f[1]=1,f[2]=1。

变式2:使用公式Ack(m,n)=Ack(m-1,Ack(m,n-1)),依次递归计算,递归结束条件n=0时,Ack(m,n)=Ack(m-1,1);m=0时,Ack(m,n)=n+1。



3 0
原创粉丝点击