C 多数组排列算法

标签 c arrays algorithm multidimensional-array permutation

我正在尝试编写一个程序,根据存储在多个数组中的单词列表生成排列。 例如,我的程序要求像这样的 2 组单词:

words #1: abc def ghi
words #2: 123 456

我想要的是这个输出:

abc 123 | abc 456 | def 123 | def 456 | ghi 123 | ghi 456

或者:

123 abc | 123 def | 123 ghi | 456 abc | 456 def | 456 ghi

顺序无关紧要。

我可能会创建一个非固定大小的词组数组。那么输入将是:

words #1: abc def ghi
words #2: 123 456
words #3: ** --

输出:

abc 123 ** | abc 123 -- | abc 456 ** | abc 456 -- | def 123 ** | def 123 -- | def 456 ** | def 456 -- | ghi 123 ** | ghi 123 -- | ghi 456 ** | ghi 456 --

我想我不得不考虑使用递归函数,但我有点困惑。 这是我写的:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef struct permut_word_s {
    char *str;
} permut_word_t;

typedef struct permut_group_s {
    permut_word_t *words;
    int nb_words;
} permut_group_t;

static int split(char *str,
                 char *token,
                 permut_group_t *g) {
    permut_word_t *a = NULL;
    permut_word_t *t = NULL;
    char *p = NULL;
    int nbw = 0;
    int l = 0;

    if(!str || !token || !g) {
        return -1;
    }

    p = strtok(str, token);

    while(p != NULL) {
        if(!(t = realloc(a, (nbw + 1) * sizeof(permut_word_t)))) {
            return -1;
        }
        if(!(t[nbw].str = malloc(strlen(p) + 1))) {
            return -1;
        }
        memset(t[nbw].str, 0, strlen(p) + 1);
        if(!(strncpy(t[nbw].str, p, strlen(p)))) {
            return -1;
        }
        nbw++;
        p = strtok(NULL, token);
        a = t;
    }

    g->words = a;
    g->nb_words = nbw;

    return 0;
}

void word_free(permut_word_t *w) {
    if(!w) {
        return;
    }

    if(w->str) {
        free(w->str);
    }

    return;
}

void group_free(permut_group_t *g) {
    int i = 0;

    if(!g) {
        return;
    }

    for(; i < g->nb_words; i++) {
        if(&g->words[i]) {
            word_free(&g->words[i]);
        }
    }

    free(g->words);
    return;
}

void permut(permut_group_t *g,
            int cur,
            int len) {
    int i = 0;
    int j = 0;

    if(cur == len) {
        return;
    }

    for(i = cur; i < len; i++) {
        for(j = 0; j < g[cur].nb_words; j++) {
            printf("%s ", g[cur].words[j].str);
        }
        permut(g, cur + 1, len);
    }
}

int main(int argc, char **argv) {
    char buf[1024] = { 0 };
    permut_group_t *groups = NULL;
    int len = 0;

    (void)argc;
    (void)argv;

    if(!(groups = malloc(2 * sizeof(permut_group_t)))) {
        return -1;
    }

    fprintf(stdout, "words #1: ");
    fgets(buf, 1024, stdin);
    split(buf, " ", &groups[0]);
    len++;

    fprintf(stdout, "words #2: ");
    fgets(buf, 1024, stdin);
    split(buf, " ", &groups[1]);
    len++;

    permut(&groups[0], 0, len);

    group_free(&groups[0]);
    group_free(&groups[1]);
    free(groups);

    return 0;
}

如何正确知道组数组可能具有可变大小?

最佳答案

尝试以下操作:

void permut(permut_group_t *g,
            int cur,
            int len, char *result=NULL) {
    int j = 0;

    if(cur == len) {
        printf("%s\n", result);
        return;
    }

    for(j = 0; j < g[cur].nb_words; j++) {
        char nextLine[200];
        if (cur==0)
            strncpy (nextLine, g[cur].words[j].str, 200);
        else
            snprintf (nextLine, 200, "%s;%s", result, g[cur].words[j].str);

        permut(g, cur + 1, len, nextLine);
    }
}

下面的输入

words #1: AB CD
words #2: 11 22 33

然后产生以下输出:

AB;11
AB;22
AB;33
CD;11
CD;22
CD;33

诀窍是在收集结果时,必须保留中间获得的组合并将其传递到下一个级别。因此,函数 permut 的签名已通过(可选)参数 char* result 进行扩展,该参数用作这些中间(或最终)组合的“内存”。

置换函数的签名现在是permut(permut_group_t *g, int cur, int len, char *result=NULL);从函数 main 中,您可以保持调用 permut(&groups[0], 0, len) 不变,因为可选参数 result 可以是参数cur为0时省略;

请注意,我还扩展了函数 split 以去除任何尾随的新行,这样这些新行就不会被复制到结果中:

char *newLine = strrchr(str, '\n');
if (newLine)
    *newLine = '\0';

关于C 多数组排列算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41632437/

相关文章:

java - 如何找到数组对象的中位数?

ios - 需要按钮多次重复相同的功能

c++ - 在 Polymorph 设计中使用数组

c++ - float 和双重比较最有效的方法是什么?

正则表达式与cfg交集的算法

c - 如何检查当前是否设置了闹钟?

从 C 检查 OCaml 类型签名

c - getaddrinfo 似乎在 Windows 和 Ubuntu 之间返回不同的结果?

c - 查找二叉树中最左边的节点

c - realloc() 上的运行时错误 |中序遍历