递归算法详解

来源:互联网 发布:grub如何进入linux系统 编辑:程序博客网 时间:2024/05/27 02:30

1递归:
          (1)终止条件 :  如果不满足条件,就不进行递归调用。            
    (2
)一个递归调用语句  :  该递归调用语句的参数应该逐渐逼近不满足条件,以至最后断绝递归。       
    (3)先测试,后递归调用。   

  在递归函数定义中,必须先测试,后递归调用。也就是说,递归调用是有条件的,满足了条件后,才可以递归。

步骤:

1. 归纳出“递推”规则
2. 找出“递归结束”的条件,称为递归出口。

#include <iostream>#include<vector>using namespace std;long gcdr(int a,int b){if(a%b==0)return b;return gcdr(b,a%b);}long gcdl(int a,int b){while(b!=0){int temp= a%b;  a=b;b= temp;}return a;}int main(int argc, char* argv[]){    cout<<gcdl(72,32);    //9    return 0;}

4:各式各样利用递归的问题

1:首先看看那些传统的问题吧,如使用递归来解决斐波那契数列的第n个数是多少?(开始从1开始) 

写程序的时候我测试了一下,假如要第100个数字,那我们对比一下不使用的递归的时候时间消耗

[cpp] view plaincopyprint?
  1. #include <iostream>  
  2. #include <ctime>  
  3. using namespace std;  
  4.   
  5. int Fib2(int index);  
  6. int Fib1(int index);  
  7. int main(int argc, char* argv[])  
  8. {  
  9.     clock_t start,finish;  
  10.   
  11.     cout<<"不使用递归:"<<endl;  
  12.     start = clock();  
  13.     cout<<"所得结果为 "<<Fib2(40)<<endl;  
  14.     finish = clock();  
  15.     cout<<"时间消耗为 "<<finish - start<<"毫秒"<<endl;  
  16.   
  17.     cout<<endl;  
  18.     cout<<"使用递归:"<<endl;  
  19.     start = clock();  
  20.     cout<<"所得结果为 "<<Fib1(40)<<endl;  
  21.     finish = clock();  
  22.     cout<<"时间消耗为 "<<finish - start<<"毫秒"<<endl;  
  23.   
  24.     system("pause");  
  25.     return 0;  
  26. }  
  27.   
  28. int Fib1(int index)  
  29. {  
  30.     if(index==1 || index==2)  
  31.         return index;  
  32.     else  
  33.         return Fib1(index-1) + Fib1(index-2);    //开始递归调用  
  34. }  
  35.   
  36. int Fib2(int index)  
  37. {  
  38.     if(index == 1 || index ==2)  
  39.         return index;  
  40.     int *array = new int [index+1];  
  41.     array[1]=1;                //第0个元素没有使用  
  42.     array[2]=2;  
  43.     for(int i=3;i<=index;++i)  
  44.         array[i] = array[i-1] + array[i-2];  
  45.     return array[index];  
  46. }  


运行结果:

结果显而易见,差距太明显,在这里我们同时求第40个斐波那契数字比较时间消耗,所以大家可以看到递归的时间消耗是非常严重,在可以不用递归的时候尽量不用,有很多题用一般的思路是很难解的,或者是过程繁琐,如果适当的利用递归,结果将事半功倍!!!

 

 2:递归的汉诺塔

这个程序以及说明在分治算法那一节已经说了,递归和分治通常都是结合在一起使用的,一次次的缩小范围,而且子问题和原问题具有相同的结构!

[cpp] view plaincopyprint?
  1. #include <stdio.h>    
  2. #include <stdlib.h>    
  3.     
  4. static int count = -1;    
  5.     
  6. void move(char x,char y);                             // 对move函数的声明     
  7. void hanoi(int n,char one,char two,char three)       ;// 对hanoi函数的声明\    
  8.     
  9. int main()    
  10. {              
  11.     int m;    
  12.     printf("请输入一共有多少个板子需要移动:");    
  13.     scanf("%d",&m);    
  14.     printf("以下是%d个板子的移动方案:\n",m);    
  15.     hanoi(m,'A','B','C');    
  16.     system("pause");    
  17.     return 0;    
  18. }    
  19.     
  20. void hanoi(int n,char one,char two,char three)        // 定义hanoi函数      
  21. // 将n个盘从one座借助two座,移到three座     
  22. {            
  23.     if(n==1)    
  24.         move(one,three);    
  25.     else    
  26.     {    
  27.         hanoi(n-1,one,three,two);                   //首先把n-1个从one移动到two    
  28.         move(one,three);                            //然后把最后一个n从one移动到three    
  29.         hanoi(n-1,two,one,three);                   //最后再把n-1个从two移动到three    
  30.     }    
  31. }    
  32.         
  33. void move(char x,char y)                           //  定义move函数     
  34. {    
  35.     count++;    
  36.     if( !(count%5) )    
  37.         printf("\n");    
  38.     printf("%c移动至%c  ",x,y);    
  39. }    


3:整数的划分问题

将一个整数分解为若干个整数之和的形式,比如 n = n1+n2+n3+n4··········!不同划分的个数称为N的划分数。

例如对于6而言:

6;

5+1;

4+2,4+1+1;

3+3;3+2+1;3+1+1+1;

2+2+2;2+2+1+1;2+1+1+1+1;

1+1+1+1+1+1     一共有6种!

1、 q(n,1) = 1 ,n>=1 ;
当最大加数不大于1时,任何正整数n只有一种表示方式:n = 1+1+……+1 。n个1的和。
2、q( n,m ) = q( n,n ),n<=m;  最大加数不能大于n。
3、 q( n,n ) = 1 +  q( n , n-1 );   正整数的划分由n1=n和n1<=n的划分组成。
4、q( n,m ) = q( n,m-1 )+q( n-m,m ), n>m>1;正整数n的最大加数不大于m的划分由 n1=m的划分和n1<m的划分组成。

现在可以依据这个递推原理写出程序:

[cpp] view plaincopyprint?
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. int intPart( int n , int m ) ;  
  4. int main()  
  5. {  
  6.     int num ;  
  7.     int partNum = 0 ;  
  8.     printf("Please input an integer:/n") ;  
  9.     scanf("%d",&num) ;  
  10.     partNum = intPart(num,num);  
  11.     printf("%d/n",partNum) ;  
  12.     system("pause");  
  13.     return 0;  
  14. }  
  15. int intPart( int n , int m )  
  16. {  
  17.     if( ( n < 1 ) ||( m < 1 ) ) return 0 ;  
  18.     if( ( n == 1 )||( m == 1 ) ) return 1 ;  
  19.     if( n < m ) return intPart( n , n ) ;  
  20.     if( n == m ) return intPart( n , m-1 ) + 1 ;  
  21.     return intPart( n , m-1 ) + intPart( n - m , m ) ;  
  22. }  
运行结果可以看到一共有11种情况

4. 整数的全排列问题:

全排列的递归实现也就是不停的交换两个数的位置.

[cpp] view plaincopyprint?
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. void swap(char *a,char *b)  
  5. {  
  6.     char temp = *a;  
  7.     *a = *b;  
  8.     *b = temp;  
  9. }  
  10. //k表示循环到第几个字符,m表示该次循环的总长度  
  11. void arrange(char *pizstr,int k,int m)  
  12. {  
  13.     if(k == m)  
  14.     {  
  15.         static int m_count = 1;  
  16.         printf("the %d time:%s\n",m_count++,pizstr);  
  17.     }  
  18.     else  
  19.     {  
  20.         for(int i=k;i<=m;i++)                          //主要递归球全排列的代码  
  21.         {  
  22.             swap(pizstr+k,pizstr+i);  
  23.             arrange(pizstr,k+1,m);  
  24.             swap(pizstr+k,pizstr+i);  
  25.         }  
  26.     }  
  27. }  
  28. void foo(char *p_str)  
  29. {  
  30.     arrange(p_str,0,strlen(p_str)-1);  
  31. }  
  32. int main()  
  33. {  
  34.     char pstr[] = "12345";  
  35.     printf("%s\n",pstr);  
  36.     foo(pstr);  
  37.     system("pause");  
  38.     return 0;  
  39. }  

0 0
原创粉丝点击