题目要求:用C写一个函数, 如 Foo(const char *str), 打印出 str 的全排列,
如 abc 的全排列: abc, acb, bca, dac, cab, cba
通过观察可以发现全排列的方式:把每个元素依次放到第一个位置,剩下的元素再全排列,直到最后一个元素进行全排列(即它本身),所以可以用递归实现。
如a,b,c的全排列:Foo("abc")
1. 首先提出元素a,剩下的元素b,c全排列Foo("bc");
2. Foo("bc")全排列,提出b, 剩下的c全排列Foo("c");
3. Foo("c")只有一个元素,结果就是它本身。然后交换bc,执行2步骤
4. b,c全排列结束后,交换a,b 执行步骤1。
这里要注意的是在执行步骤1时,要将排列顺序恢复到原来顺序。
代码:
#include <stdio.h>
void permutation(char s[], int begin, int end)
{
if( (0 <= begin) && (begin <= end) )
{
if( begin == end ) //排列到最后一个元素了,打印结果
{
printf("%s\n", s);
}
else
{
int i = 0;
for(i=begin; i<=end; i++)
{
char temp;
temp = s[begin]; //将a, b, c每个元素一次放到前面,a(b,c); b(a,c); c(b,a);
s[begin] = s[i];
s[i] = temp;
permutation(s, begin+1, end); //全排列剩下的元素
temp = s[begin]; //恢复到原来的顺序
s[begin] = s[i];
s[i] = temp;
}
}
}
}
int main()
{
char s[] = "abc";
permutation(s, 0, 2);
return 0;
}
这里在实现的时候没有考虑元素有重复的情况。
下面考虑有重复元素的情况,例如abb,或者aba等情况。之前是把每个元素都放入第一个位置,剩下的元素继续全排列。 这里只要把重复的元素找到,不再对其进行放到第一个位置 对其余元素全排列就好了,这样就跳过了重复排列的情况。
#if 1
#include <stdio.h>
static int count = 0;
/**
* 查找是否是重复的元素
* 如果是重复元素,返回1,否则返回0
**/
int isDuplicated(const char* s, int begin, int end)
{
int i = 0;
int ret = 0;
for(i=begin; i<end; i++)
{
if(s[i] == s[end])
{
ret = 1;
break;
}
}
return ret;
}
void permutation(char s[], int begin, int end)
{
if( (0 <= begin) && (begin <= end) )
{
if( begin == end ) //排列到最后一个元素了,打印结果
{
printf("第 %d 个排列:", ++count);
printf("%s\n", s);
}
else
{
int i = 0;
for(i=begin; i<=end; i++)
{
char temp;
if(!isDuplicated(s, begin, i)) //保证不对重复的元素再进行全排列
{
temp = s[begin]; //将a, b, c每个元素一次放到前面,a(b,c); b(a,c); c(b,a);
s[begin] = s[i];
s[i] = temp;
permutation(s, begin+1, end); //全排列剩下的元素
temp = s[begin]; //恢复到原来的顺序
s[begin] = s[i];
s[i] = temp;
}
}
}
}
}
int main()
{
char s[] = "12341";
permutation(s, 0, 4);
return 0;
}
#endif