在说递归之前,我给大家说一个小故事,故事就是在说递归之前,我给大家说一个小故事,故事就是在说递归之前,我给大家说一个小故事,故事就是在说递归之前,我给大家说一个小故事,故事就是在说递归之前我给大家说一个小故事......
这个故事的名字就叫做递归。。。哈哈。
故事虽然有点扯淡,但它却很好的解释神马叫做递归。
递归的正式定义:
在数学和计算机科学中,递归指由一种(或多种)简单的基本情况定义的一类对象或方法,并规定其他所有情况都能被还原为其基本情况。
例如,下列为某人祖先的递归定义:
某人的双亲是他的祖先(基本情况)。
某人祖先的双亲同样是某人的祖先(递归步骤)
更多的定义请自行百度~~~,以下我说下我对于递归的体会:
1,递归说白了就是自己调用自己
2,能用其他方法解决的问题,就尽量不要使用递归(可能不正确,只是我的个人体会),耗用内存较大,尤其在 Java中尽量避免使用。
3,递归的调用是基于栈的
4,解决某个问题时,将其切割成n份,先执行1的操作,再进行n-1的操作,以此类推下去。
递归有几个经典的算法,这里给列出以下:
===============================分割线~~=============================================
案例1: 反转字符串
这里我用两种方式实现了,均采用递归方式。
1,源码:
- // 递归.cpp : 定义控制台应用程序的入口点。
- //
-
- #include "stdafx.h"
- #include
-
- void reverse_str(char * str)
- {
- if((NULL != str) &&(*str != '\0'))
- {
- reverse_str(str + 1);
- printf("%c",*str);
- }
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- reverse_str("woshi ni erdaye");
- printf("\n");
- system("pause");
- return 0;
- }
运行结果:
- eyadre in ihsow
- 请按任意键继续. . .
2,有一定局限性,需要结尾字符判断
- // 递归.cpp : 定义控制台应用程序的入口点。
- //
-
- #include "stdafx.h"
- #include
- void reverse_str_2()
- {
- char ch;
- ch = getchar();
- if (ch != '.')//以.结束
- {
- reverse_str_2();
- }
- printf("%c",ch);
- }
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- reverse_str_2();
- printf("\n");
- system("pause");
- return 0;
- }
运行结果:
- haha gaga xixi.
- .ixix agag ahah
- 请按任意键继续. . .
==================================================================================
案例2:Fibonacci数列
斐波那契数列,又称黄金分割数列,指的是这样一个数列:1、1、2、3、5、8、13、21、……在数学上,斐波纳契数列以如下被以递归的方法定义:F1=,F2=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1963起出版了以《斐波纳契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。
- #include "stdafx.h"
- #include
-
- int fibonacci(int n)
- {
- if(n==0)
- {
- return 0;
- }
- if(n == 1)
- {
- return 1;
- }
- if(n > 0)
- {
- return fibonacci(n-1) + fibonacci(n-2);
- }
- }
-
- int main()
- {
- int n = 10;
- for ( int i=0; i<=n; i++)
- {
- int val = fibonacci(i);
- printf("n = %d\t fibonacci = %d\n",i,val);
- }
-
- system("pause");
- return 0;
- }
运行结果:
- n = 0 fibonacci = 0
- n = 1 fibonacci = 1
- n = 2 fibonacci = 1
- n = 3 fibonacci = 2
- n = 4 fibonacci = 3
- n = 5 fibonacci = 5
- n = 6 fibonacci = 8
- n = 7 fibonacci = 13
- n = 8 fibonacci = 21
- n = 9 fibonacci = 34
- n = 10 fibonacci = 55
- 请按任意键继续. . .
================================================================================
案例3:汉诺塔问题
汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
- #include "stdafx.h"
- #include
-
- void hannuo(int n,char a,char b,char c)
- {
- if(n == 1)
- {
- printf("%c -> %c \n",a,c);
- }
- if(n>1)
- {
- hannuo(n-1,a,c,b);
- printf("%c -> %c \n",a,c);
- hannuo(n-1,b,a,c);
- }
- }
-
- int main()
- {
- hannuo(3,'A','B','C');
- system("pause");
- return 0;
- }
运行结果:
- A -> C
- A -> B
- C -> B
- A -> C
- B -> A
- B -> C
- A -> C
- 请按任意键继续. . .
================================分割线啦===================================
案例4:实现strlen
strlen()函数是C函数库中求字符串长度的函数,这里用递归实现它~
- #include "stdafx.h"
- #include
-
- int strlen(const char * str)
- {
- if (str == NULL)
- {
- return -1;
- }
- else if (*str == '\0')
- {
- return 0;
- }
- else
- {
- return strlen(str + 1) + 1;
- }
-
- }
-
- int main(void)
- {
- char * str1 = "";
- printf("The length of str1 is : %d\n",strlen(str1));
- char * str2 = NULL;
- printf("The length of str2 is : %d\n",strlen(str2));
- char * str3 = "wo shi yi ge zi fu chuan lalala~";
- printf("The length of str3 is : %d\n",strlen(str3));
-
- system("pause");
- return 0;
- }
运行结果:
- The length of str1 is : 0
- The length of str2 is : -1
- The length of str3 is : 32
- 请按任意键继续. . .
====================================================================================
案例5:全排列
在初中的时候,数学课上我们就学过了排列与组合。那啥叫全排列呢,比如abc 全排列的结果是: abc acb bac bca cab aba一共六种可能,解释完毕~
- #include "stdafx.h"
- #include
-
-
- void quanpailie(char *s ,int b,int e)
- {
- if((b>=0) && (b<=e))
- {
- if(b == e)
- {
- printf("%s\n",s);
- }
- else
- {
- int i;
- for(i=b; i<=e; i++)
- {
- char c = s[b];
- s[b] = s[i];
- s[i] = c;
-
- quanpailie(s, b+1, e);
-
- c = s[b];
- s[b] = s[i];
- s[i] = c;
- }
- }
- }
- }
-
- int main()
- {
- char s[] = "abcd";
-
- quanpailie(s, 0, 3);
-
- system("pause");
- return 0;
- }
运行结果:
- abcd
- abdc
- acbd
- acdb
- adcb
- adbc
- bacd
- badc
- bcad
- bcda
- bdca
- bdac
- cbad
- cbda
- cabd
- cadb
- cdab
- cdba
- dbca
- dbac
- dcba
- dcab
- dacb
- dabc
- 请按任意键继续. .
首先,递归,你可以想想成循环。for循环也可以看作类似递归的东西。但是for循环和递归有个本质区别在于,for循环,是在循环外,进行判断,以决定是否直接退出。而递归,是在循环体内判断,是否退出本次循环。这里就有两个差别了。
1、并不是说for循环不能在循环体内跳出,完全可以,但是希望强调,这个判断是针对循环体独立的,所以我说循环外,而递归的判断是针对每次的具体的循环而不是对整体循环是否停止做判断。
2、for跳出循环体,则前面的循环均不会再重现,而递归是退回到上一次的循环。
上面两者合起来就是我说的比较本质的区别。由此递归,是行为上循环。而每次循环,均属于自己独立的空间。而多次循环是累加,嵌套的。
你可以把递归看做到楼顶取东西。从一楼爬,看,不是的,继续爬,每层楼梯看上去都一样,你执行的过程都一样,但是实际上,1到2,2到3的楼梯是两个楼梯,等你到楼顶了,取了东西,你不能直接就跳楼,还得从楼顶一层层退回来。
而驴子拉磨,则属于for循环。无论跑多少次,都是在原地。变化的只是磨盘里磨的东西,而不是驴每圈所在的不同位置
《Thinking In Algorithm》09.彻底理解递归~~http://blog.csdn.net/speedme/article/details