递归思想运用很灵活,有时可以显而易见,有时却需要深入琢磨,这里我们练习一个题目,题目内容是输出n个字符的所有排列。

利用前面博客中回顾的递归知识,深入分析此题目,

我们先依次取n个字符中的一个作为第一位上的值,问题则转化为求得剩下n-1个字符的所有排列,依此类推,问题越来越简化,简化,最简单情况就是各位置上字符都被确定,排列结束。

代码示例:

 1 /* arrangement.c --- 
 2  * 
 3  * Filename: arrangement.c
 4  * Description: 列出长度为n的字符串的所有排列
 5  * Author: magc
 6  * Maintainer: 
 7  * Created: 一  8月  6 08:49:16 2012 (+0800)
 8  * Version: 
 9  * Last-Updated: 一  8月  6 11:17:26 2012 (+0800)
10  *           By: magc
11  *     Update #: 94
12  * URL: 
13  * Keywords: 
14  * Compatibility: 
15  * 
16  */
17 
18 /* Commentary: 
19  * 由递归思想来分析化解此问题
20  * 分解第一步:先依次从n个字符中选择1个字符,即先确定1位,然后再求得剩下n-1个字符的所有排列,可以发现重复的递归子问题,但原问题与子问题也是不尽相同。
21  * 针对这种原问题与递归子问题不对称时,可以通过一个函数包装器,然后再通过一个辅助函数来解决更普遍的子问题。
22  * 巧妙运用字符交换来实现某位置上字符值
23  */
24 
25 /* Change Log:
26  * 
27  * 
28  */
29 
30 /* Code: */
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 typedef char * string;
40 
41 void arrange(string mystr,int p);
42 void swapCharactor(string mystr,int i,int k);
43 
44 
45 int main(int argc, char * argv[])
46 {
47     string str;
48     char s[] = "ABCD";
49     str = s;
50     arrange(str,0);
51     printf("\n");
52     
53 }
54 /*************************************************************************
55 *功能描述:排列字符
56 *参数列表:mystr是指定的字符串;p是指字符串中已经确定的位数
57 *返回类型:
58 **************************************************************************/
59 void arrange(string mystr,int p){ 
60 
61     int i;
62     int len = strlen(mystr);
63     if(p == len){                         //当所有位都已经确定是,当前排列结束,输出内容
64         printf("%s,",mystr);
65     }else{
66         for(i = p;i < len;i++){           //由已经确定位数,找出未确定字符的所有组合
67             swapCharactor(mystr,p,i)  ;
68             arrange(mystr,p + 1);
69             swapCharactor(mystr,i,p);//还原前面的交换结果,为了是后面继续与其它字符交换
70         }
71     }
72     
73 }
74 /*************************************************************************
75 *功能描述:交换两个位置上的字符
76 *参数列表:
77 *返回类型:
78 **************************************************************************/
79 void swapCharactor(char * mystr,int i,int k){
80     char temp ;
81     temp = mystr[i];
82     mystr[i] = mystr[k];
83     mystr[k] = temp;
84     
85 }
86 
87 
88 /* arrangement.c ends here */

在GCC下编译输出的结果:

注:
1)体会分析问题,找到递归子问题,遇到原问题与递归子问题不对称的时候可以借助函数包装器,再用一个辅助函数专门处理递归子问题,
2)找到递归问题的最简单情景(即作为递归出口),然后使问题朝此情景不断转化,
3) 体会这个通过字符交换的方式来实现某位置字符更换

 

此题目参考自《程序设计抽象思想--C语言描述》,在此对作者二十年前的作品表示敬意.