我试图创建一个功能,该功能可以置换一个单词的所有可能组合,并且程序会创建置换字符串的副本,我无法弄清楚原因。
这是我的工作代码:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char arr[5000] = {0};
void swap (char *x, char *y);
void permute(char *ptr, size_t i, size_t n);
int main(void){
char str[80] = "MICHI";
size_t len = strlen(str);
permute(str, 0, len );
printf("%s\n", arr);
printf("END\n");
}
void swap (char *x, char *y){
char temp;
temp = *x;
*x = *y;
*y = temp;
}
void permute(char *ptr, size_t i, size_t n){
size_t j;
if (i == n){
strcat (arr, ptr);
strcat (arr, "\n");
}else{
for (j = i; j <= n; j++)
{
swap( (ptr + i), (ptr + j) );
permute(ptr, i+1, n);
swap( (ptr + i), (ptr + j) );
}
}
}
这是输出:
ABC
AB
ACB
AC
A
A
BAC
BA
BCA
BC
B
B
CBA
CB
CAB
CA
C
C
END
预期产出应为:
ABC
AB
ACB
AC
A
BAC
BA
BCA
BC
B
CBA
CB
CAB
CA
c
该程序会创建大量重复项,并且还会创建大量新行。
注意到如果INPUT是例如MICHI
,我会得到这样的重复:
IMCHI
IMCH
IMCIH
IMCI
答案 0 :(得分:3)
您在排列中包含字符串终止符\0
。
line
的内部状态是:
ABC\0
AB\0C
ACB\0
AC\0B
A\0CB
A\0BC
BAC\0
BA\0C
BCA\0
BC\0A
B\0AC
B\0CA
CBA\0
CB\0A
CAB\0
CA\0B
C\0AB
C\0BA
\0ABC
\0ACB
\0BAC
\0BCA
\0CAB
\0CBA
printf
仅打印到结尾0
。
解决此问题的一种方法是将循环限制减少一个,并从排列中排除\0
。然后,您必须添加第二个循环,该循环创建一个排除i
个字符的子字符串,并为该子字符串调用permute
。
另一种方法是在分支超出\0
时停止置换。
修改强>
这是第二个建议的实现,即如果排列与前一个排列相同,则通过抑制输出来“停止置换”。它甚至似乎产生了你在例子中指定的顺序:
void permute(char *ptr, size_t i, size_t n){
size_t j;
static char prev[80] = "";
if (i == n){
if (strcmp(prev, ptr)) {
strcat (arr, ptr);
strcat (arr, "\n");
strcpy(prev, ptr);
}
}else{
for (j = i; j <= n; j++)
{
swap( (ptr + i), (ptr + j) );
permute(ptr, i+1, n);
swap( (ptr + i), (ptr + j) );
}
}
}
答案 1 :(得分:2)
函数permute中的循环包含字符串的NUL字节。您只需将j <= n
更改为j < n
即可。
像这样:
void permute(char *ptr, size_t i, size_t n){
size_t j;
if (i == n){
strcat (arr, ptr);
strcat (arr, "\n");
}else{
for (j = i; j < n; j++)
{
swap( (ptr + i), (ptr + j) );
permute(ptr, i+1, n);
swap( (ptr + i), (ptr + j) );
}
}
}