关于递归

/*刚学编程不久,对于递归不太熟悉,于是今天干脆仔细看看递归这一块~*/

/*下面是此时此刻的学习心得~*/

/*没什么好说的  看看题目就明白递归是怎么回事了~*/

题目:求问题Z

思考:

(1)我们发现:要想解决问题Z,只需要解决稍简单点的问题Y,要想解决问题Y只需解决稍简单点的问题W,

                      要想解决问题W只需解决稍简单点的问题V,要想解决问题V只需解决稍简单点的问题U

                       …………要想解决问题B只需要解决稍微简单点的问题A。

(2)我们发现:从Z到Y再到W再到V…………再到A都遵循同样的规律

(3)我们发现:问题A可以相当容易的得到结果

因此只要告诉计算机(2)(3),计算机就一定会告诉我们答案。

 

今天首先了解了递归的概念,如上,概似高中数学学的数列的递推公式- -,还是很通俗易懂的。

但是无奈应了那句话----“看得明,写不出”。

因此想要真正灵活的掌握递归思想,一定是需要做题写程序来积累的。

 

 

(为服务于本文,下面的程序都用递归来写,虽然有的用递归是个很糟糕的选择= =#)

 

从题目中去感悟~~~

Q1:求n!

       要想知道n![因为n!=n*(n-1)!]所以就要先知道(n-1)![因为(n-1)!=(n-1)*(n-2)!]]所以就要先知道(n-2)!…………最后只需知道1!即可。

       符合本文开头所说的(2)(3),所以可以用递归来解决。

       按照本文开头所说,只需告诉计算机(2)(3)即可。

                         1                     (n=0时)

        即 n!=

                          nx(n-1)        (n=1,2,3…时)

       转化成程序语言即:

 

关于递归
 1  #include<iostream.h>
 2  int factorial(int n)
 3  {
 4       int y;
 5       if(n==0) y=1;
 6       else y=n*factorial(n-1);
 7       return y;
 8   }
 9   void main()
10   {
11       int n;
12      cin>>n;
13      cout<<factorial(n)<<endl;
14  }
关于递归

 

    

 

Q2:经典的汉诺塔:ABC三根柱子,将n个圆盘从A移动到B,可以借助C。(一次只能移动柱子最上端的一个圆盘;小圆盘上不能放大圆盘)

     

       要想将n个盘子从A移动到B,可以a:将n-1个盘子从A移动到C。b:将最下面的即第n个盘子从A移动到B。c:将n-1个盘子从C移动到B。

     (由此可见要想解决n个盘子的移动,只需要解决n-1个盘子的移动)

       n-1个盘子的移动也可以照搬上面,只需要解决n-2个盘子的移动…………要想解决2个盘子的移动,只需要解决1个盘子的移动。

       符合本文开头所说的(2)(3),所以可以用递归来解决。

       按照本文开头所说,只需告诉计算机(2)(3)即可。

              1      (n=1)    

f(n)=

               f(n-1)+1+f(n-1)  (n=2,3,4…)

       转化成程序语言即:

关于递归
#include<iostream.h>
void hanoi(int n,char a,char b,char c)
{
    if(n==1)cout<<a<<"->"<<b<< ;
    else
    {
        hanoi(n-1,a,c,b);                //将n-1个从A移到C
        cout<<a<<"->"<<b<< ;           //将第n个从A移到B
        hanoi(n-1,c,b,a);                //将n-1个从C移到B
    }
}
void main()
{
    int n;
    cin>>n;
    hanoi(n,A,B,C);
}
关于递归

Q3:斐波那契数列。

      鸡个数问题:一 小鸡出生第三天生下一只小鸡。假设第一天只有一只刚出生的小鸡,问第n天一共有多少只鸡。

 

       要想递归,关键是找到每一层之间的结构规律!!!经分析得第n天鸡的个数等于第n-1天鸡的个数 加上 n-2天前存在的鸡在第n天生下的小鸡数

       因此要想知道第n天鸡的个数只需要知道第n-1天和第n-2天…………以此类推,最终只需要知道第0天和第1天鸡的个数。

                        0(n=0)

        f(n)=     1(n=1)

                        f(n-1)+f(n-2)   (n=2,3,4,5…)

 

         转化成程序语言即:

关于递归
 1 #include<iostream>
 2 using namespace std;
 3 int num(int day)
 4 {
 5     
 6     if(day==0)return 0;
 7     if(day==1)return 1;
 8     return num(day-1)+num(day-2);
 9     
10 }
11 void main()
12 {
13     int day;
14     cin>>day;
15     cout<<num(day)<<endl;
16 }
关于递归


一次走1阶或者2阶,爬n层阶梯的方法

分析得,如果最后一步为1阶,只需要知道爬n-1层的方法;如果最后一步为2阶,只需要知道爬n步的方法。

因此f(n)=f(n-1)+f(n-2)  又是斐波那契数列~~!

音符问题:若将4分音符打n拍的时间,用4分音符和2分音符来填充,共有多少种节奏?(4分音符的时值是2分音符的1/2)

 

分析得,如果最后的是四分音符则只需要知道n-1拍共有多少种节奏;如果最后是二分音符,则只需要知道n-2拍共有多少种节奏。

因此f(n)=f(n-1)+f(n-2)  和爬楼梯毫无二致 斐波那契数列。

Q4:画树(共n层枝丫):树的树干叉开长出两根树枝,每根树枝又叉开长出两根树枝,每根树枝又叉开长出两根树枝…………

发现递归结构:一个树枝分叉成两个树枝

再次强调:递归,把握结构是关键!!!!

 

 

 

 分析:从树冠到树干依次是第1到n层。

         f(画n层)=画第n层+f(画n-1层)

         f(画n-1层)=画第n-1层+f(画n-2层)

         ……

         最后推至

         f(画1层)=画第1层+f(画0层)

         f(画0层)=什么也不画

 

符合本文开头的(2)(3),每层存在一定的规律,可逐步简化,并且简化的最终问题可解。

代码如下:

关于递归
 1 void drawtree(int n) //画n层的树的枝丫
 2 {
 3     if(n==0);
 4     else
 5     {
 6         left();       //左转
 7         forward(n);   //前进n步,画第n层的树枝
 8         drawtree(n-1);//画n-1层的树的枝丫
 9         back(n);      //后退n步
10         right();      //右转
11 
12         right();      //右转
13         forward(n);   //前进n步,画第n层的树枝
14         drawtree(n-1);//画n-1层的树的枝丫
15         back(n);      //后退n步
16         left();       //左转
17 
18 
19     }
20 }
关于递归

Q5:把一个整数转换为字符形式。例如:给出一个值4267,我们需要依次产生字符‘4’,‘2’,‘6’,‘7’

 递归在这里有改变字符输出顺序的作用~

关于递归
 1 #include<iostream>
 2 using namespace std;
 3 void f(int n)
 4 {
 5     char c=n%10+48;
 6     if(n/10==0)cout<<c<< ;
 7     else
 8     {
 9             f(n/10);
10             cout<<c<< ;
11     }
12 }
13 int main()
14 {
15     int num;
16     cin>>num;
17     f(num);
18     return 0;
19 } 
关于递归

Q6:判断奇数还是偶数(递归不仅包含自己调用自己,还有交互递归,见代码)

 

关于递归
 1 #include<iostream.h>
 2 bool iseven (int);
 3 bool isodd(int n)
 4 {
 5     return  !iseven(n);
 6 }
 7 bool iseven(int n)
 8 {
 9     if(n==0)return true;
10     else return isodd(n-1);
11 }
12 void main()
13 {
14     int n;
15     cin>>n;
16     cout<<isodd(n);
17 }
关于递归

Q7:二分查找(指数爆炸的威力大家都知道吧,二分法在大量数据中进行查找时会发挥巨大的威力!)

       二分查找具体怎么回事,直接上例子就明了了,因为每一次查找都用一样的方式,所以其中一定要用到递归。

       e.g.

关于递归
/*在0~999中找500这个数*/
#include<iostream.h>
int bin_search(int*p,int low,int high,int key);
void main()
{
    int a[1000];
    for(int i=0;i<1000;i++)a[i]=i;
    cout<<bin_search(a,0,999,2000)<<endl;    //2分法查找
}
int bin_search(int*p,int low,int high,int key )
{
    int mid=(low + high) / 2; 
    if(p[mid]==key)return 1; //要找的数正好是中值
    if (low > high)  return   0;  
    if(key>p[mid])bin_search(p,mid+1,high,key);//要找到数大于中值 所以缩小查找范围 再进行二分查找
    else bin_search(p,low,mid-1,key);//要找的数小于中值 所以缩小查找范围 再进行二分查找
}
关于递归

Q8:判断回文数。

分析:

将要判断的数字放入数组中。

每次判断数组两端的元素是否相等,如果不相等则不是回文数,

如果相等则去掉两端的元素,再判断剩下的数组中两端的元素是否相等……

直到只剩下0个元素(偶数个元素的数组)或者1个元素(奇数个元素的数组),是回文数。

关于递归
#include<iostream.h>
#include<string.h>
int f(int low,int high,char*p,int length);
void main()
{
    char c[]="apepa";
    int length=strlen(c);
    cout<<f(0,length-1,c,length)<<endl;
}
int f(int low,int high,char*p,int length)
{
    if (length == 0 || length == 1)  
        return    1;  
    if (p[low] != p[high])  
        return    0;
    return f(low+1, high-1, p, length-2); 
}
关于递归

 

下面给出字符串反转的一个例子(与判断回文数的思路完全相同)(当然本文开头说过有些程序用递归不是一个好选择,举出这些列子只是为了加深理解递归)

关于递归
#include <iostream>  
using namespace std;  
int str_turn(int low, int high, char *p, int length)  
{  
    char   temp;  
    if (length == 1 || length == 0 )  
    {  
        return    0;  
    }  
    p[low] = p[high];  
    p[high] = temp;  
  
    return str_turn(low+1, high-1, p, length-2);  
}  
int main()  
{  
    char str[]="test";  
    str_turn(0, strlen(str)-1, str, strlen(str));  
    cout << str;  
    return    0;  
}  
关于递归

 

 

 

 

 

做了这些题之后,虽然都是一些很简单的小题目,但是也算从不知道什么是递归到与递归相识相知啦~_~,也领略了它的一些神奇的魅力~~~

 

所以贴出来,和大家一起分享~

 

因为是初学,所以本文只能在最简单的层面上来运用递归,但是自以为对初学来说是相当有益的~希望对大家的递归入门有所帮助啦~~~~

 

 

感谢http://blog.csdn.net/cbs612537/article/category/1287535 ~ 对我的入门帮助很大~

 

 

              

关于递归

上一篇:读取键盘录入


下一篇:MyLineNumberReader