递归算法详解
来源:互联网 发布:dnf自动存装备源码 编辑:程序博客网 时间:2024/06/05 04:13
递归算法详解
C语言通过运行时堆栈来支持递归的调用,在我们刚接触递归的时候,国内很多教材都采用求阶乘和菲波那契数列来描述该思想,就如同深受大家敬爱的国产的C语言程序设计,老谭也用了阶乘来描述递归,以至于很多新手一看见阶乘就理所当然的认为是递归,坑了不少人,说实在的,描述这个思想还是可以,但是利用递归求阶乘可是没有一点好处,递归解决菲波那契数列效率更是低得惊人,这点是显而易见的!废话不多说,接下来我们进入正题!(不过说实话,我很讨厌接下来这些太理论的东西,说到底就是那么个意思,大家懂就好了,也可以当看看故事!我主要说的就是各种各样递归的实例)
1:递归算法的思想
递归算法是把问题转化为规模缩小了的同类问题的子问题。然后递归调用函数(或过程)来表示问题的解。在C语言中的运行堆栈为他的存在提供了很好的支持,过程一般是通过函数或子过程来实现。
递归算法:在函数或子过程的内部,直接或者间接地调用自己的算法。
2:递归算法的特点:
3:递归算法的要求
4:各式各样利用递归的问题
1:首先看看那些传统的问题吧,如使用递归来解决斐波那契数列的第n个数是多少?(开始从1开始)
#include <iostream>using namespace std;int Fib(int index);int main(int argc, char* argv[]){cout<<Fib(12)<<endl;system("pause");return 0;}int Fib(int index){if(index==1 || index==2)return index;elsereturn Fib(index-1) + Fib(index-2); //开始递归调用}
写程序的时候我测试了一下,假如要第100个数字,那时间可不知道等了多久,调用函数达到了上千次,速度太慢,对于这种情况,我们对比一下不使用的递归的时候时间消耗,这里只需要多加一个函数即可
#include <iostream>#include <ctime>using namespace std;int Fib2(int index);int Fib1(int index);int main(int argc, char* argv[]){clock_t start,finish;cout<<"不使用递归:"<<endl;start = clock();cout<<"所得结果为 "<<Fib2(40)<<endl;finish = clock();cout<<"时间消耗为 "<<finish - start<<"毫秒"<<endl;cout<<endl;cout<<"使用递归:"<<endl;start = clock();cout<<"所得结果为 "<<Fib1(40)<<endl;finish = clock();cout<<"时间消耗为 "<<finish - start<<"毫秒"<<endl;system("pause");return 0;}int Fib1(int index){if(index==1 || index==2)return index;elsereturn Fib1(index-1) + Fib1(index-2); //开始递归调用}int Fib2(int index){if(index == 1 || index ==2)return index;int *array = new int [index+1];array[1]=1; //第0个元素没有使用array[2]=2;for(int i=3;i<=index;++i)array[i] = array[i-1] + array[i-2];return array[index];}
运行结果:
结果显而易见,差距太明显,在这里我们同时求第40个斐波那契数字比较时间消耗,所以大家可以看到递归的时间消耗是非常严重,而且效率非常低下,上面已经说了,在可以不用递归的时候尽量不用,那么递归是不是一无是处勒?答案是否定的,在很多程序设计大赛中,有很多题用一般的思路是很难解的,或者是过程繁琐,如果适当的利用递归,结果将事半功倍!!!
2:递归的汉诺塔
这个程序以及说明在分治算法那一节已经说了,递归和分治通常都是结合在一起使用的,一次次的缩小范围,而且子问题和原问题具有相同的结构! 这里我直接把汉诺塔代码拷贝过来,就不多说了!
#include <stdio.h> #include <stdlib.h> static int count = -1; void move(char x,char y); // 对move函数的声明 void hanoi(int n,char one,char two,char three) ;// 对hanoi函数的声明\ int main() { int m; printf("请输入一共有多少个板子需要移动:"); scanf("%d",&m); printf("以下是%d个板子的移动方案:\n",m); hanoi(m,'A','B','C'); system("pause"); return 0; } void hanoi(int n,char one,char two,char three) // 定义hanoi函数 // 将n个盘从one座借助two座,移到three座 { if(n==1) move(one,three); else { hanoi(n-1,one,three,two); //首先把n-1个从one移动到two move(one,three); //然后把最后一个n从one移动到three hanoi(n-1,two,one,three); //最后再把n-1个从two移动到three } } void move(char x,char y) // 定义move函数 { count++; if( !(count%5) ) printf("\n"); printf("%c移动至%c ",x,y); }
3:兔子繁殖问题(递归实现)
一对小兔子一年后长成大兔子,一对大兔子每半年生一对小兔子,大兔子的繁殖期为4年,兔子的寿命为6年,假定第一年年初投放了一对小兔子,请编程实现,第N年年末总共有多少只兔子,N由键盘输入!
解析,这个题目比较好懂,也就是一对小兔子前一年长大,然后每半年产一对小兔子,持续4年,然后最后一年不生殖了,再过一年死亡,题目看似简单,其实要想递归起来可不是那么容易的,大家可以想一下!
代码如下:
4:整数的划分问题
将一个整数分解为若干个整数之和的形式,比如 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的划分组成。
现在可以依据这个递推原理写出程序:
#include <stdio.h>#include <stdlib.h>int intPart( int n , int m ) ;int main(){ int num ; int partNum = 0 ; printf("Please input an integer:/n") ; scanf("%d",&num) ; partNum = intPart(num,num); printf("%d/n",partNum) ; system("pause");return 0;}int intPart( int n , int m ){ if( ( n < 1 ) ||( m < 1 ) ) return 0 ; if( ( n == 1 )||( m == 1 ) ) return 1 ; if( n < m ) return intPart( n , n ) ; if( n == m ) return intPart( n , m-1 ) + 1 ; return intPart( n , m-1 ) + intPart( n - m , m ) ;}运行结果可以看到一共有11种情况
5 整数的全排列问题:
全排列的递归实现也就是不停的交换两个数的位置,题目描述这里就省了,直接上代码!
#include <stdio.h>#include <stdlib.h>#include <string.h>void swap(char *a,char *b){char temp = *a;*a = *b;*b = temp;}//k表示循环到第几个字符,m表示该次循环的总长度void arrange(char *pizstr,int k,int m){if(k == m){static int m_count = 1;printf("the %d time:%s\n",m_count++,pizstr);}else{for(int i=k;i<=m;i++) //主要递归球全排列的代码{swap(pizstr+k,pizstr+i);arrange(pizstr,k+1,m);swap(pizstr+k,pizstr+i);}}}void foo(char *p_str){arrange(p_str,0,strlen(p_str)-1);}int main(){char pstr[] = "12345";printf("%s\n",pstr);foo(pstr);system("pause");return 0;}
时间紧促,有时间再继续举例!持续更新
- 递归算法详解-
- 递归算法详解
- 递归算法详解
- 递归算法详解
- 递归算法详解
- 递归算法详解
- 递归算法详解
- 递归算法详解
- C#递归算法详解
- 递归算法详解
- C#递归算法详解
- 递归算法详解
- 全排列递归算法详解
- 25_递归算法详解
- C#算法—递归详解
- 经典算法详解 之 递归算法
- Fibonacci数列的递归与非递归实现算法详解
- 二叉树中序遍历非递归算法详解
- Tomcat 7的安装和配置步骤
- osg 基本几何图元
- Android 应用界面简单的输入法代码
- 冒泡排序
- Linux下建立自定义命令的过程
- 递归算法详解
- eclipse配合opencv的设置
- 【C】单词统计
- 类的接口和抽象类
- XML第十七讲:根据Schema生成XML文档
- Fence Repair
- Hibernate延迟加载Session关闭的解决方案
- Windows环境下Android NDK环境搭建
- 《COM技术内幕》图摘