递归思想博大而精深,巧妙而精简,需要慢慢体会.

知识点小结:

  问题经过泛化之后,定义一个函数包装器,这个包装器是相对规范的,暂且叫它递归模型,它由两部分组成,一是递归出口,即问题的最简单情景,二是递归体,它是用来解决子问题的,使子问题向最简单情况转化,注意一定是使问题越来越简单。

代码实例1:生成费波那契序列

 1 /* fibonacci.c --- 
 2  * 
 3  * Filename: fibonacci.c
 4  * Description: 费波那契序列
 5  * Author: magc
 6  * Maintainer: 
 7  * Created: 四  8月  2 09:35:28 2012 (+0800)
 8  * Version: 
 9  * Last-Updated: 四  8月  2 12:04:49 2012 (+0800)
10  *           By: magc
11  *     Update #: 75
12  * URL: 
13  * Keywords: 
14  * Compatibility: 
15  * 
16  */
17 
18 /* Commentary: 
19  * 费波那契序列:1,1,2,3,5,8,13,21....
20  * 形成递归的子问题就是根据前两项之和得出当前值,
21  * 
22  */
23 
24 /* Change Log:
25  * 
26  * 
27  */
28 
29 /* Code: */
30 
31 #include <assert.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <limits.h>
35 #include <string.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 
40 void fiboSeqence(int *seq , int len);
41 void outputSeq(int *seq , int len);
42 
43 
44 int main(int argc, char * argv[])
45 {
46     printf("请输入一个整数n,将输出费波那契前n项:\n");
47     int n;
48     int res = scanf("%d",&n);
49     int *seq = malloc(sizeof(int) * n);
50     if(seq == NULL)error("no memory available!\n");
51     
52     fiboSeqence(seq,n);
53     outputSeq(seq,n);
54     free(seq);
55 }
56 /*************************************************************************
57 *功能描述:输出序列的内容
58 *参数列表:
59 *返回类型:
60 **************************************************************************/
61 void outputSeq(int *seq , int len)
62 {
63     int i;
64     for (i = 0; i < len; i++) {
65         printf("%d,",seq[i]);
66     }
67     printf("\n");
68 }
69 /*************************************************************************
70 *功能描述:形成递归的子问题是根据前面两项值之和确定当前值,此函数的使命就是根据这个关系,确定第len个的值。
71 *参数列表:
72 *返回类型:
73 **************************************************************************/
74 void fiboSeqence(int *seq , int len)
75 {
76     //鉴于此序列前两项特殊,从第三项开始才有规律,所以将前两项作为递归出口
77     if(len == 1)  //递归出口
78         {
79             seq[0] = 1;
80             return;
81         }
82     if(len == 2)//递归出口
83         {
84             seq[0] = 1;
85             seq[1] = 1;
86             return;
87         }
88     fiboSeqence(seq ,len - 1 );//若得到第len个值,就先得到第len-1个值
89     seq[len-1] = seq[len-2] + seq[len - 3];//解决递归子问题:第len个值是由它前两项之和得出,它依赖于先确定它前面的值,所以得放到递归调用后面。
90 }
91 
92 
93 /* fibonacci.c ends here */

注 :

1)分析费波那契序列的规律,可以看出从第三项开始具有的规律,形成递归的子问题就是当前值是由其前面两项之和得出,
2)通过一个动态数组来存放此序列。

3)递归结束的出口就是此序列的前两项

在GCC编译运行结果是:

 

 

 

代码示例2:汉诺塔经典问题

 1 /* hanota.c --- 
 2  * 
 3  * Filename: hanota.c
 4  * Description: 汉诺塔
 5  * Author: magc
 6  * Maintainer: 
 7  * Created: 五  8月  3 10:34:43 2012 (+0800)
 8  * Version: 
 9  * Last-Updated: 五  8月  3 14:47:24 2012 (+0800)
10  *           By: magc
11  *     Update #: 72
12  * URL: 
13  * Keywords: 
14  * Compatibility: 
15  * 
16  */
17 
18 /* Commentary: 
19  * 汉诺塔经典问题
20  * 有三个圆柱A,B,C,将A柱子上的n个下大上小依次叠放的圆盘移动到B上,
21  * 移动规则:一次只移动一个盘子,且保证每个柱子上的盘子都是下边大,上面小的顺序
22  * 最简单的情况是A上只剩下一个,直接从A移动到B上。
23  * 分析问题,例如有8个盘子,若将8个盘子从A到B,问题分解为将A上面7个盘子移到C作为临时存放,将A上第8个移动到B,再将C上7个移动到B。
24  * 将7个盘子从C到B问题又可分解为,将上面6个盘子移动到A上临时存放,将第七个盘子从C到B,以此类推
25  * 符合将问题分析为更简单,并且具有相同特点的问题。
26  * 
27  */
28 
29 /* Change Log:
30  * 
31  * 
32  */
33 
34 /* Code: */
35 #include <assert.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <limits.h>
39 #include <string.h>
40 #include <stdarg.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 
44 void hanota(int n,char src,char dest,char temp);
45 void moveTower(char src,char dest);
46 
47 int main(int argc, char * argv[])
48 {
49     //为三个圆柱编号
50     char A = 'A',B = 'B',C = 'C';
51     hanota(3,A,B,C);
52     
53     //目标是将A上的8个圆盘移到B上去
54     
55 }
56 /*************************************************************************
57 *功能描述:移动汉诺塔上的盘,
58 *参数列表:n代表共几个盘子,src代表源位置,dest代表要移动的目标柱子,temp代表作为临时存放的第三个柱子
59 *返回类型:
60 **************************************************************************/
61 void hanota(int n,char src,char dest,char temp){
62 
63     if(n == 1){                  //最简单情况,只有一个时,直接移动到目标柱子上
64         moveTower(src,dest);
65     }
66     else{
67         hanota(n-1,src,temp,dest);//第一步:将上面n-1个盘子移动到临时柱子上
68         moveTower(src,dest);      //第二步:将第n个盘子移动目标柱子上
69         hanota(n-1,temp,dest,src);//第三步:将临时柱子上的移动到目标柱子上
70     }
71     
72 }
73 
74 /*************************************************************************
75 *功能描述:将某个圆盘从一个柱子上移到另一个柱子上
76 *参数列表:
77 *返回类型:
78 **************************************************************************/
79 void moveTower(char src,char dest){
80     printf("由%c移动到%c\n",src,dest);
81     
82 }
83     
84 
85 
86 
87 
88 /* hanota.c ends here */

注:
1)体会递归问题的分解过程,问题泛化,得到函数包装器hanota,用来解决子问题,通过最简单情况作为递归的出口。
2)注意分析问题的过程,把握实质,如三个柱子,有多少个盘子需要表示,而每个盘子编号并不重要的,

在GCC下编译运行的结果是:

 3、Scrable拼字游戏,要求将一组字母重新排列组成一个单词的能力,输出所有可能的字母组合