全排列的递归实现
例如(a, b, c):
1>以a开头后面跟着(b, c)的所有排列
2>以b开头后面跟着(a, c)的所有排列
3>以c开头后面跟着(a, b)的所有排列
后面以此类推(递归实现)
void swap(char& a, char& b) //交换字符串
{
int temp;
temp = a;
a = b;
b = temp;
}
bool IsSwap(char *a, int begin, int end) //判断是否有重复字符串
{
for(int i=begin; i<end; i++)
{
if(a[i]==a[end])
return false;
}
return true;
}
//递归实现
void premutations(char* a, int k, int m)
{
int i=0;
static iCount=1;
if(k==m) //输出字符串
{
cout << iCount++ << " ";
for(i=0; i<=m; i++)
{
cout << a[i] << " ";
}
cout << endl;
}
else
{
for(i=k; i<=m; i++)
{
if(IsSwap(a, k, i)) //判断是否有重复字符,如果没有则交换
{
swap(a[i], a[k]);
premutations(a, k+1, m);
swap(a[i], a[k]);
}
}
}
}
非递归全排列算法,即按字典序排列算法
基本思想是:
1.对初始队列进行排序,找到所有排列中最小的一个排列Pmin。
2.找到刚刚好比Pmin大比其它都小的排列P(min+1)。
3.循环执行第二步,直到找到一个最大的排列,算法结束。
如排列ABCDE,这是所有排列中最小的一个排列,刚好比ABCDE大的排列是:ABCED。
算法如下:
给定已知序列P = A1A2A3.....An
对P按字典排序,得到P的一个最小排列Pmin = A1A2A3....An ,满足Ai > A(i-1) (1 < i <= n)
从Pmin开始,找到刚好比Pmin大的一个排列P(min+1),再找到刚好比P(min+1)大的一个排列,如此重复。
1.从后向前(即从An->A1),找到第一对为升序的相邻元素,即Ai < A(i+1)。
若找不到这样的Ai,说明已经找到最后一个全排列,可以返回了。
2.从后向前,找到第一个比Ai大的数Aj,交换Ai和Aj。
3.将排列中A(i+1)A(i+2)....An这个序列的数逆序倒置,即An.....A(i+2)A(i+1)。因为由前面第1、2可以得知,A(i+1)>=A(i+2)>=.....>=An,这为一个升序序列,应将该序列逆序倒置,所得到的新排列才刚刚好比上个排列大。
4.重复步骤1-3,直到返回。
void nonCirPermutation(char *a, int k, int m)
{
sort(a, a+m); //将数组中元素进行升序排序
do
{
copy(a, a+m+1, ostream_iterator<char>(cout, " ")); //copy函数将数组a[0,m+1)中的元素以此在标准输出流cout上输出,每个被输出的元素后面都跟随一个空格符(" ")
cout << endl;
} while (next_permutation(a, a+m+1)); //a[0,m+1) 左闭右开,next_permutation只会对与前面一个不同的字符串进行全排列
}
测试代码:
int main(void)
{
char a[] = "21232";
cout << "全排列算法递归实现 by kate19930802" << endl;
cout << "字符串 " <<a << " 的全排列" << endl;
premutations(a, 0, strlen(a)-1);
//nonCirPermutation(a, 0, strlen(a)-1);
return 0;
}