Chinaunix首页 | 论坛 | 博客
  • 博客访问: 332904
  • 博文数量: 54
  • 博客积分: 446
  • 博客等级: 下士
  • 技术积分: 821
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-30 17:37
文章分类

全部博文(54)

文章存档

2015年(35)

2014年(19)

我的朋友

分类: C/C++

2015-03-19 19:33:06

定义一个数组,编程打印它的全排列。比如定义:

#define N 3
int a[N] = { 1, 2, 3 };

则运行结果是:

$ ./a.out
1 2 3 
1 3 2 
2 1 3 
2 3 1 
3 2 1 
3 1 2 
1 2 3

程序的主要思路是:

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

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

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

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


解题过程:

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

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

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

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

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

    (3) 当 N = 3的时候,数组为 [1, 2, 3]
          a. 
把1放在 a[0] 的位置(原本也是如此,a[0] = a[0]),打印2,3的全排列(即a[1], a[2]的全排列)

                       1  2  3

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

                       2   1  3

                       2   3  1                        

                  打印完后再换回原来的位置,即1还是恢复到a[0],2还恢复到a[1]的位置
         c.  
 把3放在a[0]的位置 (这时候需要交换的是原数组的a[0]和a[2]),然后打印1, 2的全排列
                      

                       3   2  1

                       3   1  2                        

                  打印完后再换回原来的位置,即1还是恢复到a[0],3还恢复到a[2]的位置,
         至此全排列完成
 (4)N = 4, 5, 6....的思路与此相同

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #define N 3
  3.   
  4. int a[N];
  5.   
  6. void perm(int); /*求数组的全排列 */
  7. void print();
  8. void swap(int, int);//交换前缀
  9.   
  10. int main(){
  11.     int i;
  12.     for(i = 0; i<N; i++){
  13.         a[i] = i + 1;
  14.     }
  15.     perm(0);
  16. }
  17.   
  18. void perm(int offset){
  19.     int i, temp;
  20.     if(offset == N-1){
  21.         print();
  22.         return;
  23.     }else{
  24.         for(i = offset;i < N; i++){
  25.             swap(i, offset);//交换前缀
  26.             perm(offset + 1);//递归
  27.             swap(i, offset);//将前缀换回来,继续做前一次排列
  28.         }
  29.     }
  30. }
  31.   
  32. void print(){
  33.     int i;
  34.     for(i = 0; i < N; i++)
  35.         printf(" %d ",a[i]);
  36.     printf("/n");
  37. }
  38.   
  39. void swap(int i, int offset){
  40.     int temp;
  41.     temp = a[offset];
  42.     a[offset] = a[i];
  43.     a[i] = temp;
  44. }
完成了上述要求之后再考虑第二个问题:如果再定义一个常量M表示从N个数中取几个数做排列(N == M时表示全排列),原来的程序照如下方式修改:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.   
  4. #define N 4
  5. #define M 3
  6.    
  7. int a[N]; /* N个数 */
  8. int temp[M]; /* 从N个数中选出的M个数 */
  9.    
  10. void perm(int, int); /* 排列 */
  11. void swap(int, int); /* 交换两个数 */
  12. void print(); /* 打印 */
  13.    
  14. int main(){
  15.     int i;
  16.     int start = 0;//起始位置
  17.     int count = M;//排列到个数
  18.     for(i = 0; i < N; i++){
  19.         a[i] = i + 1;
  20.     }
  21.     perm(start, count);
  22. }
  23.    
  24. void perm(int offset, int count){
  25.     int i;
  26.     if( count == 0 ){
  27.         print();
  28.         return;
  29.     }else{
  30.         for(i = offset; i < N; i++){
  31.             temp[offset] = a[i];
  32.             swap(offset, i);
  33.             perm(offset+1, count-1);
  34.             swap(offset, i);
  35.         }
  36.     }
  37. }
  38.    
  39. void swap (int offset, int i){
  40.     int another;
  41.     another = a[offset];
  42.     a[offset] = a[i];
  43.     a[i] = another;
  44. }
  45.    
  46. void print(){
  47.     int i;
  48.     for(i = 0; i < M; i++)
  49.         printf(" %d ",temp[i]);
  50.     printf("/n");
  51. }
最后再考虑第三个问题:从N个数中取M个数做组合,

先看一个例子:
            C(5,3) = 10
               1 2 3
               1 2 4
               1 2 5
               1 3 4
               1 3 5
               1 4 5
               2 3 4
               2 3 5
               2 4 5
               3 4 5

分析
               1 | 2 3
               1 | 2 4
               1 | 2 5
               1 | 3 4
               1 | 3 5
               1 | 4 5
 
              ------ C(4, 2)∵可以在{2, 3, 4, 5}中挑2个出来。


               2 | 3 4
               2 | 3 5
               2 | 4 5
 
              ------ C(3, 2)∵可以在{3, 4, 5}中挑2个出来。


               3 | 4 5 
              ------ C(2, 2)∵只能在{4, 5}中挑2个出来。
               
这样就很容易写出递归算法来:

点击(此处)折叠或打开

  1. Algorithm combination(n, k, A[l..n+l-1]
  2. if k = 0
  3.    print ary[1..k]
  4. else
  5.    for i←1 to n-k+1
  6.        ary[index++] = A[l+i-1]
  7.        combination(n-i, k-1, A[l+i..n+l-1]
  8.        --index
  9.    endfor
源代码如下:



点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.   
  4. #define N 4
  5. #define M 3 
  6.    
  7. int a[N]; /* N个数 */
  8. int temp[M]; /* 从N个数中选出的M个数 */
  9. int top;
  10.    
  11. void comb(int, int); /* 组合 */
  12. void swap(int, int); /* 交换两个数 */
  13. void print(); /* 打印 */
  14.    
  15. int main(){
  16.     int i;
  17.     int start = 0;//起始位置
  18.     int count = M;//排列到个数
  19.     for(i = 0; i < N; i++){
  20.         a[i] = i + 1;
  21.     }
  22.     comb(start, count);
  23. }
  24.    
  25. void comb(int offset, int count){
  26.     int i;
  27.     if( count == 0 ){
  28.         print();
  29.         return;
  30.     }else{
  31.         for(i = offset; i < N - count + 1; i++){
  32.             temp[top++] = a[i]; 
  33.             comb(i+1, count-1);
  34.             --top;
  35.         }
  36.     }
  37. }
  38.     
  39. void print(){
  40.     int i;
  41.     for(i = 0; i < M; i++)
  42.         printf(" %d ",temp[i]);
  43.     printf("/n");
  44. }



   



          
阅读(1383) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~