排列问题的递归方法

对一组数字输出其全排列

设R= {r1,r2,...,rn}是要进行排列的n个元素, Ri = R - {ri}。集合X中元素的全排列记为perm(X )。 (ri)perm(X)表示在全排列perm(X)的每一个排列前加上前缀ri得到的排列。R的全排列可归纳定义如下:

  当 n = 1 时, perm(R) = (r),其中r是集合R中唯一的元素。

  当 n > 1 时, perm(R)由(r1)perm(R1),(r2)perm(R2),...,(r3)perm(R3)构成。

比如:把1,2,3三个数进行全排列,程序的主要思路是:

  把第1个数换到最前面来(本来就在最前面),准备打印1xx,再对后两个数2和3做全排列。

  把第2个数换到最前面来,准备打印2xx,再对后两个数1和3做全排列。

  把第3个数换到最前面来,准备打印3xx,再对后两个数1和2做全排列。

 可见这是一个递归的过程,把对整个序列做全排列的问题归结为对它的子序列做全排列的问题。

  解题过程:

   (1) 当 N = 1的时候,则直接打印数列即可。

   (2) 当 N = 2的时候,设数组为 [a, b]

            打印a[0], a[1] (即a,b)

            交换a[0],a[1]里面的内容

            打印a[0],a[1]   (此时已变成了 [b, a] )

    (3) 当 N = 3的时候,数组为 [a, b, c]

 把a放在 a[0] 的位置(原本也是如此,a[0] = a[0]),打印b,c的全排列(即a[1], a[2]的全排列)
                       a  b  c

                       a  c  b

 把b放在a[0]的位置(这时候需要交换原数组的a[0]和a[1]),然后打印a, c的全排列
                       b   a  c

                       b   c  a                       

 打印完后再换回原来的位置,即a还是恢复到a[0],b还恢复到a[1]的位置

 把c放在a[0]的位置(这时候需要交换的是原数组的a[0]和a[2]),然后打印a, b的全排列
             c  b  a
             c  a  b
 打印完后再换回原来的位置,即a还是恢复到a[0],b还恢复到a[1]的位置,至此,全排列完成
 当 N = 4,5,6,……的时候,以此类推。

C语言程序:
 1 #include<stdio.h>
 2 //全排列问题
 3 void perm(int *a, int k, int m)
 4 {
 5     int i;
 6     int temp;
 7 
 8     if(k == m)
 9     {
10         for(i = 0; i <= m; ++i)
11             printf("%d", a[i]);
12         printf("\n");
13     }
14     else
15     {
16         for(i = k; i <= m; ++i)
17         {
18             temp = a[i];                //依次将第k个元素与剩余元素交换
19             a[i] = a[k];
20             a[k] = temp;
21             perm(a, k + 1, m);          //对数组a进行除第k个元素外的所有元素全排列
22             temp = a[i];                //排列完成后换回原来的位置
23             a[i] = a[k];
24             a[k] = temp;
25         }
26     }
27 }
28 
29 int main(void)
30 {
31     int b[4] = {1,2,3,4};
32     perm(b, 0, 3);
33 
34     return 0;
35 }

不过这样存在一点小小的缺陷:两个相同的数也进行了交换

代码改进

 去掉重复符号的全排列:在交换之前可以先判断两个符号是否相同,不相同才交换,这个时候需要一个判断符号是否相同的函数。 


 1 #include<stdio.h>
 2 //全排列问题
 3 int isSwap(int *a, int nBegin, int nEnd)  //判断是否相等,如果相等则不交换
 4 {
 5     int i;
 6 
 7     for(i = nBegin; i < nEnd; i++)
 8         if (a[i] == a[nEnd])
 9             return 0;
10         return 1;
11 }
12 
13 void perm(int *a, int k, int m)
14 {
15     int i;
16     int temp;
17 
18     if(k == m)
19     {
20         for(i = 0; i <= m; ++i)
21             printf("%d", a[i]);
22         printf("\n");
23     }
24     else
25     {
26         for(i = k; i <= m; ++i)
27         {
28             if(isSwap(a, k, i) )
29             {
30                 temp = a[i];                //依次将第k个元素与剩余元素交换
31                 a[i] = a[k];
32                 a[k] = temp;
33                 perm(a, k + 1, m);          //对数组a进行除第k个元素外的所有元素全排列
34                 temp = a[i];                //排列完成后换回原来的位置
35                 a[i] = a[k];
36                 a[k] = temp;
37             }
38         }
39     }
40 }
41 
42 int main(void)
43 {
44     int b[4] = {1,2,3,4};
45     int c[4] = {2,2,3,4};
46     perm(b, 0, 3);
47     printf("\n");
48     perm(c, 0, 3);
49 
50     return 0;
51 }

 

 

 

posted @ 2016-04-25 22:17  cp_cnblogs  阅读(263)  评论(0编辑  收藏  举报