1、字典排序

【例】 如何得到346987521的下一个

    1,从尾部往前找第一个P(i-1) < P(i)的位置

4 6 <- 9 <- 8 <- 7 <- 5 <- 2 <- 1

        最终找到6是第一个变小的数字,记录下6的位置i-1

    2,从i位置往后找到最后一个大于6的数

4 6 -> 9 -> 8 -> 7 5 2 1

        最终找到7的位置,记录位置为m

    3,交换位置i-1和m的值

4 7 9 8 6 5 2 1

    4,倒序i位置后的所有数据

4 7 1 2 5 6 8 9

    则347125689为346987521的下一个排列

 

代码实现:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 /**
 5  * dictionary sequence
 6  * count:数组中元素个数
 7  */
 8 void dicseq(int *nums,int count)
 9 {
10     int i,j,k,L;
11     int tmp;
12     int flag = 0;//标志标明是否还存在下一个排列
13     L = count-1;// 尾节点的下标,特别注意边界值,容易出现段错误
14     //从右往左扫描,是否存在相邻两个数,后一个数大于前一个数,作为判断全排列是否存在的判断
15     for(i = count - 1; i > 0; i--){
16         //仍然存在排列
17         if(nums[i] > nums[i-1]){
18             //从右往左找到第一个大于a[i-1]的数,然后对换两数
19             for(j = count-1; j > i-1; j-- ){
20                 if(nums[j] > nums[i-1]){
21                     //对换两个元素
22                     tmp = nums[j];
23                     nums[j] = nums[i-1];
24                     nums[i-1] = tmp;
25                     
26                     //翻转后半部分
27                     k = i;
28                     while(k <= (i + count -1)/2){
29                         tmp = nums[k];
30                         nums[k] = nums[L];
31                         nums[L] = tmp;
32                          L--;
33                         k++;
34                     }
35                 break;//从右往左找到第一个就终止
36                 }
37             }
38             for(k = 0; k < count; k++){
39                 if(k%10 == 0)
40                     printf("\n");
41                 printf("%d\t",nums[k]);
42                 if(k == count -1)
43                     printf("\n");
44                 
45             }
46         flag = 1;//如果从右往左全是递增,那么就不存在其余的全排列,flag就永远是0,不必再递归
47         break;//该函数一次调用找出一个全排列
48         }
49         
50     }
51     if(flag)
52         dicseq(nums,count);//递归找出所有的排列,此处存在一个问题,问题规模很大时候会段错误
53 }
54 
55 
56 /*
57  *the first argument is count of number
58  **/
59 int main(int argc, char *argv[]){
60 int count, numb;
61 int i;
62 int *nums;
63 int position;
64 int dest;
65 if( argc < 2){
66     printf("too few argument\n");
67 //    free(nums);
68     return 1; 
69     exit(1);
70 }
71 
72 printf("input number is %s\n",argv[1]);
73 count = atoi(argv[1]);
74 nums = (int *)malloc(sizeof(int)*count);
75 printf("please input:\n");
76 for(i = 0; i < count; i++){
77     scanf("%d",nums+i);
78 }
79 dicseq(nums,count);
80 }
View Code

 

2、递归

上述的字典排序,可以简单的求出一个全排列的一下个排列,一个的下一个就是这两个全排列之间没有其它的全排列。当可以求出一个全排列的下一个排列,那么使用递归就可以求出所有的全排列。

假设所求全排列的字符串为,abcdefgf 8个字符组成,那么采用递归求其全排列的一种思路就是,首先要分解问题,将问题规模变小,同时问题的形式不变。采用如下两步:

  1. 原问题问题等价于分别以a、b、c、d、e、f、g为首字母,对剩余其他的7个字母进行全排列的求解。如果abcdefg都是数字的话,这种方法求出来的全排列可能不是字典序的,因为这8个数字可能不是按顺序排列的,如果要按字典序排列,我们可以先对字符串排序,然后进行全排列。
  2. 当所求全排列的字符只有一个时,不用再次调用函数递归,说明这次全排列已经完成,直接打印即可。

 

对 问题规模为n的字符串,当选定一个数字作为首字母,那么第一次需要递归函数 n 次,也就是对字符串后面的n-1个字符进行全排列,这用一个循环完成,在循环体中调用自身函数。每次选用一个字符作为已定前缀中的部分时,需要将该字符和后面的字符进行交换一次。

实现代码:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 /**
 4  * nums:数组的首地址,l:数组的首元素的下标,r:数组尾元素的下标
 5  * 该函数会打印出nums所有元素的全排列,不会改变nums元素的位置
 6  */
 7 void recurseq(int *nums, int l, int r)
 8 {
 9     int i;
10     int tmp;
11     i = 0;
12     if(l ==    r){
13         while(i <= r){
14             if(i%10 == 0)
15                 printf("\n");
16                 printf("%d\t",nums[i]);
17                 ++i;
18             if(i == r+1)
19                 printf("\n");
20         }    
21     }
22     
23     
24     if(r > l){
25         //recurseq(nums, l+1, r);
26         //边界值,i取l-1才能保证nums中的第0号元素为首项,求剩余n-1项的全排列,该值较特殊
27         for(i = l-1; i <r; i++){
28             printf("l=%d,r=%d,i=%d\n",l,r,i);
29             //交换一次
30             tmp = nums[l];
31             nums[l] = nums[i+1];
32             nums[i+1] = tmp;
33             recurseq(nums, l+1, r);
34             //交换回来,恢复nums中数值的顺序
35             nums[i+1] = nums[l];
36             nums[l] = tmp;
37         }
38         
39     }
40 }
41 
42 /*
43  *the first argument is count of number
44  **/
45 int main(int argc, char *argv[]){
46 int count, numb;
47 int i;
48 int *nums;
49 int position;
50 int dest;
51 if( argc < 2){
52     printf("too few argument\n");
53 //    free(nums);
54     return 1; 
55     exit(1);
56 }
57 
58 printf("input number is %s\n",argv[1]);
59 count = atoi(argv[1]);
60 nums = (int *)malloc(sizeof(int)*count);
61 printf("please input:\n");
62 for(i = 0; i < count; i++){
63     scanf("%d",nums+i);
64 }
65 recurseq(nums, 0, count -1);
66 }
View Code

 

posted on 2016-07-14 16:39  人生一世,草木一秋。  阅读(731)  评论(0编辑  收藏  举报