• 排列问题的递归方法


    对一组数字输出其全排列

    设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("
    ");
    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("
    ");
    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("
    ");
    48     perm(c, 0, 3);
    49 
    50     return 0;
    51 }
    
    
    
     
  • 相关阅读:
    图片预加载的JS代码
    JavaScript实现漫天飞花及文字滚动特效的代码
    判断远程图片是否存在的JavaScript代码
    dos批处理命令详解
    内存虚拟盘软件XMSDSK的使用
    医学论坛(收集)
    velocity
    java开源项目 源代码
    开放源代码的全文检索引擎Lucene
    批处理命令大全
  • 原文地址:https://www.cnblogs.com/xjtuchenpeng/p/5432990.html
Copyright © 2020-2023  润新知