最近在学习《Linux C编程一站式学习》,其中,第8.3 数组应用实例:直方图的习题2中提到全排列问题。

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

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

要求:

程序要具有通用性,如果改变了N和数组a的定义(比如改成4个数的数组),其它代码不需要修改就可以做4个数的全排列(共24种排列)

思路:

  1. 把第1个数换到最前面来(本来就在最前面),准备打印1xx,再对后两个数2和3做全排列。
  2. 把第2个数换到最前面来,准备打印2xx,再对后两个数1和3做全排列。
  3. 把第3个数换到最前面来,准备打印3xx,再对后两个数1和2做全排列。
    这是一个递归的过程,把对整个序列做全排列的问题归结为对它的子序列做全排列的问题

折腾了两天,昨晚跑步的时候终于理解了思路,今天中午解决了恢复原状的bug,调试成功。代码:

    #include <stdio.h>
    #define N 4
    #define M 2
    
    int a[] = {1, 2, 3, 4};
    int count = 0;

    void print_a()
    {
        int i;
        for(i = 0; i < N; i++)
            printf("%d ", a[i]);
        printf("\n");
    }
    
    void swap(int i, int j)
    {
        int t;
        t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
    
    void param(int i)
    {
        if(i == M)
        {
            print_a();
            count++;
        }
        else
        {
            int j;
            for(j = i; j < N; j++)
            {
                swap(i, j);
                param(i+1);
                swap(i, j); //恢复原状,以便交换a[i]和a[i+2]
            }
        }
    }
    
    int main(void)
    {
        param(0);
        printf("%d\n", count);
        
        return 0;
    }

还有两个引申的问题,这个程序同样适用于第二个问题.
第三个问题暂时没想好,搞定再记录。

第二个问题:如果再定义一个常量M表示从N个数中取几个数做排列(N == M时表示全排列),原来的程序应该怎么改?

第三个问题:如果要求从N个数中取M个数做组合而不是做排列,就不能用原来的递归过程了,组合的递归过程应该怎么描述,程序如何改?

标签: none

添加新评论