递归思想运用很灵活,有时可以显而易见,有时却需要深入琢磨,这里我们练习一个题目,题目内容是输出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语言描述》,在此对作者二十年前的作品表示敬意.