我试图编写一个程序,在存储到多个数组中的单词列表上生成排列。 例如,我的程序要求提供两组这样的单词:
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;
}
如何正确地知道groups数组可能有一个可变大小?
答案 0 :(得分:1)
尝试以下方法:
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
扩展,该参数用作&#34;内存&#34;对于这些中间(或最终)组合。
置换函数的签名现在为permut(permut_group_t *g, int cur, int len, char *result=NULL)
;从函数main
开始,您可以保持调用permut(&groups[0], 0, len)
,因为当参数result
为0时,可以省略可选参数cur
;
请注意,我还扩展了函数split
,以便去除任何尾随的新行,这样这些新行不会被复制到结果中:
char *newLine = strrchr(str, '\n');
if (newLine)
*newLine = '\0';