通过重复打印排序的排列

时间:2016-04-29 08:29:30

标签: c permutation

我想用重复的字典顺序打印字符串的所有排列。我写这段代码:

char *input;

void swap(char *x, char *y);

void permute(char *str);

int factorial(int n);

void swapSort(char array[], int left, int right);

void quick_sort(char *array, int left, int right);

//void permute(char *str, char *p_ch, int length);

int main() {
    input = malloc(8 + 1 * sizeof(char));
    fgets(input, 9, stdin);
    int n = strlen(input);
    if (input[n - 1] == '\n') {
        n--;
        input[n] = '\0';
    }
    printf("Length of string: %d\n", n);
    printf("Input string: \"%s\"\n", input);
    quick_sort(input, 0, n);
    printf("sorted string: \"%s\"\n", input);
    printf("Number of permutations: %d\n", factorial(n));
    permute(input);
    //free(input);
    return 0;
}

int factorial(int n) {
    if (n == 1) return 1;
    return n * factorial(n - 1);

}


int compare(const void *a, const void *b) {
    return (*(char *) a - *(char *) b);
}


void permute(char *str) {
    int strSize = strlen(str);
    qsort(str, strSize, sizeof(char), compare);

    int endIsNotReached = true;
    int tmpSize;
    while (endIsNotReached) {

        printf("\"%s\"\n", str);
        for (tmpSize = strSize - 2; tmpSize > -1 && str[tmpSize] >= str[tmpSize + 1]; tmpSize--) {
            //do nothing
        }

        if (tmpSize > -1) {
            int j = 1 + tmpSize;
            for (int index = j; index < strSize && str[index]; index++) {
                if (str[index] < str[j] && str[index] > str[tmpSize])
                    j = index;
            }

            swap(&str[tmpSize], &str[j]);

            qsort(str + tmpSize + 1, strSize - 1 - tmpSize, sizeof(char), compare);
        }
        else {
            endIsNotReached = false;
        }
    };
}
void quick_sort(char *array, int left, int right) {
    if (left < right) {
        int boundary = left;
        for (int i = left + 1; i < right; i++) {
            if (array[i] < array[left]) {
                swapSort(array, i, ++boundary);
            }
        }
        swapSort(array, left, boundary);
        quick_sort(array, left, boundary);
        quick_sort(array, boundary + 1, right);
    }

}
void swapSort(char array[], int left, int right) {
    char tmp = array[right];
    array[right] = array[left];

    array[left] = tmp;
}


void swap(char *left, char *right) {
    char temp = *left;
    *left = *right;
    *right = temp;
}

但是当我想要打印字符串“aaa”输出只是“aaa”但我希望输出三次是“aaa”。 (另一个例子 - 输入 - “aab” - 输出 - “aab”,“aab”,“aba”,“aba”,“baa”,“baa”)

1 个答案:

答案 0 :(得分:0)

即使OP不能使用C ++及其标准库,我们也可以查看std::next_permutation的可能实现,并将其转换为C,以利用其按字典顺序排列的结果。

bool next_permutation( char *first, char *last ) {
    if (first == last)
        return false;
    char *i = last;
    if (first == --i)
        return false;

    char *i1,
         *i2;

    while (true) {
        i1 = i;
        if ( *--i < *i1 ) {
            i2 = last - 1;
            while ( *i >= *i2 ) --i2;
            swap(i, i2);
            reverse(i1, last);
            return true;
        }
        if (i == first) {
            reverse(first, last);
            return false;
        }
    }   
}

void reverse( char *first, char *last ) {
    while ((first != last) && (first != --last)) {
        swap(first, last);
        ++first;
    }
}

我想指出的是,在OP的例子中,#aaa&#34; aaa&#34;预计会重复3次,所有重复次数应为6次(或3次):

a 1 a 2 a 3
a 1 a 3 a 2
a 2 a 1 a 3
a 2 a 3 a 1
a 3 a 1 a 2
a 3 a 2 a 1

所以permute()看起来像这样:

void permute( char *str, int length ) {
    static int count = 0;
    int i, rep = 1;

    // first sort the string
    qsort(str, length, 1, compare);

    // then calculate the repetitions
    for ( i = 1; i < length; ++i ) {
        if ( str[i] == str[i - 1] )
            ++rep;
    }

    int repetitions = factorial(rep);

    do {
        ++count;        
        printf("%5d: %s\n", count, str);
    } while ( count % repetitions  ||  next_permutation(str, str + length ) );
}

我也稍微修改main()

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h> 
// this is  ^^^  for bool, but if if C99 is not an option:
//    typedef enum { false = 0, true = !false } bool;


int factorial(int n);
void swap( char *x, char *y);
void reverse( char *first, char *last );   // used by next_permutation
bool next_permutation( char *first, char *last );
void permute( char *str, int length );

enum { WORD_MAX_SIZE = 16, ARRAY_SIZE };

int main(void) {
    char input[ARRAY_SIZE];

    fgets(input, ARRAY_SIZE, stdin);
    int n = strlen(input);
    if ( input[n-1] == '\n' ) {
        --n;
        input[n] = '\0';       
    }

    printf("Length of string: %d\n", n);
    printf("Input string: \"%s\"\n", input);

    printf("Number of permutations: %d\n", factorial(n));
    permute(input, n);

    return 0;
}

int factorial( int x ) {
    int f = x;
    while ( x > 1 ) {
        f *= --x;
    }
    return f;
}

int compare(const void *a, const void *b) {
    return (*(char *) a - *(char *) b);
}

void swap(char *left, char *right) {
    char temp = *left;
    *left = *right;
    *right = temp;
}

示例:

Input string: "aba"
Number of permutations: 6
    1: aab
    2: aab
    3: aba
    4: aba
    5: baa
    6: baa

Input string: "baca"
Number of permutations: 24
    1: aabc
    2: aabc
    3: aacb
    4: aacb
    5: abac
    6: abac
    7: abca
    8: abca
    9: acab
   10: acab
   11: acba
   12: acba
   13: baac
   14: baac
   15: baca
   16: baca
   17: bcaa
   18: bcaa
   19: caab
   20: caab
   21: caba
   22: caba
   23: cbaa
   24: cbaa