题目:
输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则打印输出字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab、cba。
分析:
首先求得所有可能出现在第一个位置上的字符,即把第一个字符和后边所有的字符交换;
固定第一个字符,求后面所有字符的排列。
如abc:
第一步:将第一行数据分别和第二行和第三行数据交换
a | b | c |
b | a | c |
c | a | b |
第二步:保持第一列不变,将第二行数据分别和第三行数据交换
a | c | b |
b | c | a |
c | b | a |
交换完毕,显然,要用到递归的知识。
方法一:
源代码如下:
#include<iostream>
using std::endl;
using std::cout;
void Permutation(char *str);
void Permutation(char *str, char *begin);
void Permutation(char *str)
{
if (str == NULL)
{
cout << "Thr array is empty" << endl;
return;
}
cout << str << "的排列为:";
Permutation(str, str);
}
void Permutation(char *str, char *begin)
{
if (*begin == '\0')
cout << str << " ";
else
{
for (char *pCh = begin; *pCh != '\0'; ++pCh)
{
//交换第一个字符和当前所指向的字符
char temp = *pCh;
*pCh = *begin;
*begin = temp;
Permutation(str, begin + 1);
//变回原来的形式
temp = *pCh;
*pCh = *begin;
*begin = temp;
}
}
}
void test11()
{
cout << "\t=======测试空指针========" << endl;
Permutation(NULL);
}
void test12()
{
cout << "\t=======测试只有分隔符的指针========" << endl;
char ch[] = "";
Permutation(ch);
}
void test13()
{
cout << "\t=======测试只有一个元素的指针========" << endl;
char ch[] = "a";
Permutation(ch);
}
void test14()
{
cout << "\t=======测试只有多个元素的指针========" << endl;
char ch[] = "abc";
Permutation(ch);
}
void test15()
{
cout << "\t=======测试只有多个元素的指针========" << endl;
char ch[] = "abcd";
Permutation(ch);
}
int main()
{
test11();
cout << endl;
test12();
cout << endl;
test13();
cout << endl;
test14();
cout << endl;
test15();
cout << endl;
system("pause");
return 0;
}
运行结果:
=======测试空指针========
Thr array is empty
=======测试只有分隔符的指针========
的排列为:
=======测试只有一个元素的指针========
a的排列为:a
=======测试只有多个元素的指针========
abc的排列为:abc acb bac bca cba cab
=======测试只有多个元素的指针========
abcd的排列为:abcd abdc acbd acdb adcb adbc bacd badc bcad bcda bdca
bdac cbad cbda cabd cadb cdab cdba dbca dbac dcba dcab dacb dabc
请按任意键继续. . .
方法二:
原理和方法一相同,但是代码的实现方式略有不同。
源代码如下:
#include<iostream>
#include<cstdlib>
#include<cstdio>
using std::cout;
using std::endl;
int num = 1; //局部静态变量,用来统计全排列的个数
//k表示当前选取到第几个数,m表示公有多少个数
void Permutation3(char *pStr, int k, int m)
{
if ((pStr == NULL) || (m == 0))
return;
if (k == m)
{
printf("第%d个排列\t%s\n", num++, pStr);
}
else
{
for (int i = k; i < m; i++)
{
std::swap(*(pStr + k), *(pStr + i));
Permutation3(pStr, k + 1, m);
std::swap(*(pStr + k), *(pStr + i));
}
}
}
void test1111()
{
cout << "\t=======测试空指针========" << endl;
Permutation3(NULL, 0, 0);
}
void test1222()
{
cout << "\t=======测试只有分隔符的指针========" << endl;
char ch[] = "";
Permutation3(ch, 0, 0);
}
void test1333()
{
cout << "\t=======测试只有一个元素的指针========" << endl;
char ch[] = "a";
Permutation3(ch, 0, 1);
}
void test1444()
{
cout << "\t=======测试只有多个元素的指针========" << endl;
char ch[] = "abc";
Permutation3(ch, 0, 3);
}
void test1555()
{
cout << "\t=======测试只有多个元素的指针========" << endl;
char ch[] = "abcd";
Permutation3(ch, 0, 4);
}
int main()
{
test1111();
cout << endl;
num = 1;
test1222();
cout << endl;
num = 1;
test1333();
cout << endl;
num = 1;
test1444();
cout << endl;
num = 1;
test1555();
cout << endl;
num = 1;
system("pause");
return 0;
}
运行结果如下:
=======测试空指针========
=======测试只有分隔符的指针========
=======测试只有一个元素的指针========
第1个排列 a
=======测试只有多个元素的指针========
第1个排列 abc
第2个排列 acb
第3个排列 bac
第4个排列 bca
第5个排列 cba
第6个排列 cab
=======测试只有多个元素的指针========
第1个排列 abcd
第2个排列 abdc
第3个排列 acbd
第4个排列 acdb
第5个排列 adcb
第6个排列 adbc
第7个排列 bacd
第8个排列 badc
第9个排列 bcad
第10个排列 bcda
第11个排列 bdca
第12个排列 bdac
第13个排列 cbad
第14个排列 cbda
第15个排列 cabd
第16个排列 cadb
第17个排列 cdab
第18个排列 cdba
第19个排列 dbca
第20个排列 dbac
第21个排列 dcba
第22个排列 dcab
第23个排列 dacb
第24个排列 dabc
请按任意键继续. . .
考虑去重问题:
由于全排列就是从第一个数字起每个数分别与它后面的数字交换。我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这二个数就不交换了。如122,第一个数与后面交换得212、221。然后122中第二数就不用与第三个数交换了,但对212,它第二个数与第三个数是不相同的,交换之后得到221。与由122中第一个数与第三个数交换所得的221重复了。所以这个方法不行。
换种思维,对122,第一个数1与第二个数2交换得到212,然后考虑第一个数1与第三个数2交换,此时由于第三个数等于第二个数,所以第一个数不再与第三个数交换。再考虑212,它的第二个数与第三个数交换可以得到解决221。此时全排列生成完毕。
换种思维,对122,第一个数1与第二个数2交换得到212,然后考虑第一个数1与第三个数2交换,此时由于第三个数等于第二个数,所以第一个数不再与第三个数交换。再考虑212,它的第二个数与第三个数交换可以得到解决221。此时全排列生成完毕。
这样我们也得到了在全排列中去掉重复的规则——去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。
源代码:
#include<iostream>
using namespace std;
#include<assert.h>
//在[nBegin,nEnd)区间中是否有字符与下标为pEnd的字符相等
bool IsSwap(char* pBegin, char* pEnd)
{
char *p;
for (p = pBegin; p < pEnd; p++)
{
if (*p == *pEnd)
return false;
}
return true;
}
void Permutation4(char* pStr, char *pBegin)
{
assert(pStr);
if (*pBegin == '\0')
{
static int num = 1; //局部静态变量,用来统计全排列的个数
printf("第%d个排列\t%s\n", num++, pStr);
}
else
{
for (char *pCh = pBegin; *pCh != '\0'; pCh++) //第pBegin个数分别与它后面的数字交换就能得到新的排列
{
if (IsSwap(pBegin, pCh))
{
swap(*pBegin, *pCh);
Permutation4(pStr, pBegin + 1);
swap(*pBegin, *pCh);
}
}
}
}
int main(void)
{
char str[] = "abab";
Permutation4(str, str);
system("pause");
return 0;
}
运行结果如下:
第1个排列 abab
第2个排列 abba
第3个排列 aabb
第4个排列 baab
第5个排列 baba
第6个排列 bbaa
请按任意键继续. . .