递归是种思想,不是算法。
一个算法,你用递归去实现,它就是递归算法;你用循环去实现,它就是非递归算法。递归与循环一一对应,大多数编程语言都支持循环,但不一定支持递归。
一个大问题,分解成类似的小问题,递归只用一句话就能描述这些“重复工作”,代码那叫一个简单!想想这句话的威力都觉得很牛B!
递归算法简单而又经典的例子有:n!、Fibonacci、Hanoi、回溯、树遍历、图搜索。敲代码的时候,递归反映为func()里调用func(),当然传入的形参是不一样的,而且递归必须要有exit door(不然递归到哪天才是个头呀,一直往深了递归,stack非给溢出不可,通常100层以上的递归就会overflow了)。递归算法其实是低效的,每次递归到下一层,系统都要为这一层记录返回地址、局部变量开辟stack空间,返回上一层的时候系统还要花时间删掉这些东东,系统真累!
下面看一下Honoi示例:
#include <stdio.h>
void move(char x,char y) { printf("%c-->%c/n",x,y); } main() { int m; scanf("%d",&m); hanoi(m,'1','2','3'); } | void hanoi(int n,char one,char two,char three) { if(n==1)move(one,three); else { hanoi(n-1,one,three,two); move(one,three); hanoi(n-1,two,one,three); } } /* n>=2时, 移动分三步: step1: 把A上的n-1个圆盘移到B上; Step2: 把A上的一个圆盘移到C上; Step3: 把B上的n-1个圆盘移到C上; */ |
循环与递归是一对一的,下面给出最简单的示例:
int n=5; int a[]={1,2,3,4,5};
int main() { int sum=0; for(int i=0;i<n;i++) sum+=a[i];
sum=sum2(n-1); } | int sum2(int n) { if(n<0) return 0; else return sum2(n-1)+a[n]; }
|
假如你把算法设计成了递归形式,再用stack去模拟消递归,效果不一定就好,你只是做了系统做的事情。所以,不要盲目相信非递归算法就比递归算法效率高,如果消递归技术不好,效率还不及原来的呢。
做些练习巩固一下吧,用递归的方法完成:
1. 求数组中的最大数
2. 求n个整数的积
3. 求n个整数的平均值
4. 求n个自然数的最大公约数与最小公倍数
5. 有一对雌雄兔,每两个月就繁殖雌雄各一对兔子.问n个月后共有多少对兔子?
6. 已知:数列1,1,2,4,7,13,24,44,...求数列的第 n项.
第6题解答:
#include <stdio.h>
int main() { int n; int a[]={1,1,2};
scanf("%d",&n); int tem=sum(n); printf("%d/n",tem); return 0; } | int sum(int n) { if(n<3) return a[n]; else return sum(n-1)+sum(n-2)+sum(n-3); }
|
Ø 递归生成所有全排列
实现1:
#include <stdio.h> | int f(int dep){ |
12345,12354,12435,12453,…,54321
实现2:
设一组数p = {r1, r2, r3, ... ,rn}, 全排列为perm(p),pn = p - {rn}。因此Perm(p) = r1Perm(p1), r2Perm(p2), r3Perm(p3), ... , rnPerm(pn)。
#include <stdio.h>
int n = 0;
void swap(int *a, int *b) { int m; m = *a; *a = *b; *b = m; }
int main() { int list[] = {1, 2, 3, 4, 5}; perm(list, 0, 4); printf("total:%d/n", n); return 0; } | void perm(int list[], int k, int m) { int i; if(k > m) { for(i = 0; i <= m; i++) printf("%d ", list[i]); printf("/n"); n++; } else { for(i = k; i <= m; i++) { swap(&list[k], &list[i]); perm(list, k + 1, m); swap(&list[k], &list[i]); } } }
|
并不是严格字典序的哦,例如12345,12354,12435,12453,“12543,12534”…