zoukankan      html  css  js  c++  java
  • 产生所有排列字典顺序2013年1月23日

           问题描述:以字典顺序产生所有排列。假定集合set是连续的并且按从小到大顺序排列好了的,并且有n个元素。

           思路:算法的思路分成两个部分:A是递归产生以某个数字开头的排列,B是调用A来依次生成  1为第一位的所有排列,2为第一位的所有排列,....n为第一位的所有排列。

           下面是A部分的详细思路:

            1.以1234为例子。从右到左来寻找< (j=i+1,i>0)。

            2.接着再从右到左查找第一个比大的元素,然后将二者交换位置,再将到集合末尾逆序。这样就找到了1234的按字典顺序的下一个元素。

            3.递归进行。要注意递归的一个关键就是递归的结束条件。这里,以1开头的排列的最后一个数是1432,也就是说最后一个元素到第2个元素(第一个元素为1,肯定不能动)都没有<,也就是说,第二位及以后的元素都按照逆序排列好了,也就是找到了最后一个元素。这就是递归结束的条件。

            A部分的代码如下:

     1 //find out all of the permutation in the set with first element 1 to n.
     2 void find_next()
     3 {
     4     set_print();
     5     int index_i,index_j,index_k;
     6     flag=0;
     7     for(index_i=n-2;index_i>0;index_i--)       
     8         if(set[index_i]<set[index_i+1])
     9         {
    10             index_j=index_i+1;
    11             flag=1;
    12             break;
    13         }
    14     if(flag==0)
    15         return ;
    16     for(index_k=n-1;index_k>0;index_k--)
    17         if(set[index_k]>set[index_i])
    18             break;
    19     swap(&set[index_i],&set[index_k]);
    20     reverse(index_j,n-1);
    21     
    22     find_next();
    23 }

           下面是B部分的详细思路:        

           1.B部分的算法主要负责执行A算法之后的增大首位的转折点,举个例子,就是1432的下一个元素是2134,从首位是1变到了首位是2。

           2.当A算法执行完后,元素是1432,这时,将第4位与第1位交换,就会得到2431,那么,很容易看出除了第一位之外其余都是按照逆序排列的,2431肯定不是1432的下一个数,2431与1432之间肯定还存在有符合条件的排列。于是,将除了第一位之外的元素逆序,就可达到目的,即2134。这才是1432的下一个元素。

           3.当到达2431后,即2开头的最后一个元素,又将第3位与第一位交换,再将首位之后的元素逆序,即可得到3开头的第一个数。

           4.那么,可以总结出,当首位为1时,就将最后一位与首位交换;当首位为2时,就将倒数第2位与首位交换;当首位为3时,就将倒数第3位与首位交换.....依次类推。这其中的道理很容易想明白。这样持续n次,所有结果就都得到了。

           B部分的代码如下:

     1  int count=1;
     2     int i=n-1;
     3     while(i>=0)
     4     {
     5         set[0]=count++;
     6         find_next(); 
     7         swap(&set[0],&set[i]);
     8         reverse(1,n-1);
     9         i--;
    10     }

          完整的代码如下:

    View Code
     1 #include <stdio.h>
     2 #define MAX 1000
     3 
     4 int n=4; 
     5 int set[MAX]={1,2,3,4};
     6 int flag=0;
     7 
     8 //swap a and b
     9 void swap(int *a,int *b)
    10 {
    11     int temp=*a;
    12     *a=*b;
    13     *b=temp;
    14 }
    15 
    16 //reverse a range of a set
    17 void reverse(int start,int end)
    18 {
    19     int index_r=0;
    20     int new_end=end-start;
    21     for(index_r=0;index_r<=new_end/2;index_r++)
    22         swap(&set[index_r+start],&set[new_end-index_r+start]);
    23 
    24 }
    25 
    26 void set_print()
    27 {
    28     int index;
    29     for(index=0;index<n;index++)
    30         printf("%d ",set[index]);
    31     printf("\n");
    32 }
    33 
    34 //find out all of the permutation in the set with first element 1 to n.
    35 void find_next()
    36 {
    37     set_print();
    38     int index_i,index_j,index_k;
    39     flag=0;
    40     for(index_i=n-2;index_i>0;index_i--)       
    41         if(set[index_i]<set[index_i+1])
    42         {
    43             index_j=index_i+1;
    44             flag=1;
    45             break;
    46         }
    47     if(flag==0)
    48         return ;
    49     for(index_k=n-1;index_k>0;index_k--)
    50         if(set[index_k]>set[index_i])
    51             break;
    52     swap(&set[index_i],&set[index_k]);
    53     reverse(index_j,n-1);
    54     
    55     find_next();
    56 }
    57 
    58 int main()
    59 {
    60     int count=1;
    61     int i=n-1;
    62     while(i>=0)
    63     {
    64         set[0]=count++;
    65         find_next(); 
    66         swap(&set[0],&set[i]);
    67         reverse(1,n-1);
    68         i--;
    69     }
    70     return 0;
    71 }

     参考资料:《C语言名题精选百则技巧篇》

    如果你觉得我的文章对你有帮助,请推荐一下,非常感谢!

  • 相关阅读:
    排序与查找
    gdb
    编码风格
    数组
    结构体
    循环语句
    深入理解函数
    分支语句
    简单函数
    解决国内NPM安装依赖速度慢问题
  • 原文地址:https://www.cnblogs.com/NeilHappy/p/2873737.html
Copyright © 2011-2022 走看看