【什么是全排列】
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。用123来示例下,123的全排列有123、132、213、231、312、321这六种。
【题目】
设计一个递归算法生成n个元素{r1,r2,…,rn}的全排列。
【算法讲解】-- 递归版
设R={r1,r2,…,rn}是要进行排列的n个元素,Ri=R-{ri}。
集合X中元素的全排列记为perm(X)。
(ri)perm(X)表示在全排列perm(X)的每一个排列前加上前缀得到的排列。
R的全排列可归纳定义如下:
当n=1时,perm(R)=(r),其中r是集合R中唯一的元素;
当n>1时,perm(R)由(r1)perm(R1),(r2)perm(R2),…,(rn)perm(Rn)构成。
实现思想:将整组数中的所有的数分别与第一个数交换,这样就总是在处理后n-1个数的全排列。
#include <iostream>
using namespace std;
int total = 0;
/*
递归版本
设R={r1,r2,…,rn}是要进行排列的n个元素,Ri=R-{ri}。
集合X中元素的全排列记为perm(X)。
(ri)perm(X)表示在全排列perm(X)的每一个排列前加上前缀得到的排列。
R的全排列可归纳定义如下:
当n=1时,perm(R)=(r),其中r是集合R中唯一的元素;
当n>1时,perm(R)由(r1)perm(R1),(r2)perm(R2),…,(rn)perm(Rn)构成。
实现思想:将整组数中的所有的数分别与第一个数交换,这样就总是在处理后n-1个数的全排列。
********************************************/
template<class Type>
void Perm(Type list[], int k, int m)
{ //产生[list[k:m]的所有排列
if (k == m)
{ //只剩下一个元素
for (int i = 0; i <= m; i++)
cout << list[i];
cout << endl;
total++;
}
else //还有多个元素待排列,递归产生排列
{
for (int i = k; i <= m; i++)
{
swap(list[k], list[i]);
Perm(list, k + 1, m);
swap(list[k], list[i]); //恢复
}
}
}
template<class Type>
void swap(Type& a, Type& b)
{
Type temp;
temp = a;
a = b;
b = temp;
}
int main()
{
int s[] = { 1,2,3,4,5 };
Perm(s,0,4);
system("pause");
return 0;
}
【算法讲解】-- 非递归版字典序全排列
1、从后往前找第一个升序对(a[j] a[j+1])
2、从后往前找第一个大于a[j]的数a[k],交换这两个数
3、将j号下标之后的所有数逆序
4、重复上述三步,直至循环结束(j<0)
#include <iostream>
using namespace std;
void swap(int& a, int& b)
{
int temp;
temp = a;
a = b;
b = temp;
}
void pailie(int a[], int n)
{
int i;
int j, k;
while (1)
{
for (i = 0; i < n; i++)
cout << a[i];
cout << endl;
//从后往前找第一个升序对(a[j]a[j+1])
for (j = n - 2; j >= 0 && a[j] > a[j + 1]; j--);
//循环结束、全排列结束
if (j < 0)
return;
//从后往前找第一个大于a[j]的数a[k]
for (k = n - 1; k > j && a[k] < a[j]; k--);
//交换这两个数
swap(a[k], a[j]);
//将j号下标之后的所有数逆序
for (int l = j + 1, r = n - 1; l < r; l++, r--)
swap(a[l], a[r]);
}
}
int main()
{
int s[] = { 1,2,3,4,5 };
pailie(s,5);
system("pause");
return 0;
}