设计一个递归算法生成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,2…n,用一个数组A 来存放所生成的排列,然后输出它们。假定开始时n个元素以依次存放在数组A中,为了生成这n个元素的所有排列,可以采取下面的步骤:
(1)第一个元素为1,即排列的第一个元素为1,生成后面n-1个元素的排列。
在上面的第一步 ,为生成后面n-1个元素的排列,继续采取下面的步骤:
(1)第二个元素为2,即排列的第二个元素为2,生成后面n-2个元素的排列。
(2)第二个元素和第三个元素互换,使排列的第二个元素为3,生成后面n-2个元素的排列。
(3)如此继续,最后第二个元素和第n个元素互换,使排列的第二个元素为n,生成后面n-2个元素的排列。
这种步骤一直继续,当排列的前n-2个元素已确定后,为生成后面2个元素的排列,可以:
(1)第n-1个元素为n-1,即排列的第n-1个元素为n-1,生成后面1个元素的排列,此时n个元素已构成一个排列。
(2)第n-1个元素和第n个元素互换,使排列的第n-1个元素为n,生成后面1个元素的排列,此时n个元素已构成一个排列。
令排列算法perm(A,k,n)表示生成数组后面 个元素的排列。通过上面的分析有:
(1)基础步:k=1,只有一个元素,已构成一个排列。
(2)归纳步:对任意的k,1<k<=n完成perm(A,k-1,n),逐一对第n-k元素与第n-k~n元素进行互换,每互换一次,就执行一次perm(A,k -1,n)操作,产生一个排列。
算法可以如下描述:
void perm(int A[],int k,int n)
{
if(k==1)
PrintA(n);
else
{
for(int i=n-k+1;i<=n;i++)//初始值k=n,i=1,交换A[1]和A[1],执行perm(A,n-1,n);
//i=2,交换A[2]和A[1],执行perm(A,n-1,n);
//i=3,交换A[3]和A[1],执行perm(A,n-1,n);
{
swap(A[i],A[n-k+1]);
perm(A,k-1,n);
swap(A[i],A[n-k+1]);
}
}
}
输入
输入只有一行,输入整数n
样例输入:
3
输出
输出有n!行,输出1-n的n!种排列,每个数字中间有一个空格
样例输出:
1 2 3
1 3 2
2 1 3
2 3 1
3 2 1
3 1 2
完整代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int A[101];
void PrintA(int n)
{
for(int i=1;i<=n;i++)
cout<<A[i]<<" ";
cout<<endl;
}
//PrintA时间复杂度:O(n)
void perm(int A[],int k,int n)
{
if(k==1)
PrintA(n);
else
{
for(int i=n-k+1;i<=n;i++)//初始值k=n,i=1,交换A[1]和A[1],执行perm(A,n-1,n);
//i=2,交换A[2]和A[1],执行perm(A,n-1,n);
//i=3,交换A[3]和A[1],执行perm(A,n-1,n);
{
swap(A[i],A[n-k+1]);
perm(A,k-1,n);
swap(A[i],A[n-k+1]);
}
}
}
//perm时间复杂度:O(n!)*O(n)
int main()//1 2 3
{
int n;
cin>>n;
//赋初值
for(int i=1;i<=n;i++)
A[i]=i;
perm(A,n,n);
return 0;
}