生成一个数的全排列,对很多人来说都不是难事。通过递归或非递归的方式,可以生成全排列。对于一些题目的暴力解法是必不可少的。下面总结了几种生成全排列的方式。
1.递归不交换式(dfs):
void dfs(int dep)
{
if (dep>n)
{ check(); return;}
for (int i=1;i<=n;i++)
if (!vis[i])
{
vis[i]=1;
a[dep]=i;
dfs(dep+1);
vis[i]=0;
}
}
2 非递归交换式(用到了swap(),速度好像比DFS慢):
#include <iostream>
#include <cstring>
using namespace std;
//交换数组a中下标为i和j的两个元素的值
void swap(int *a,int i,int j)
{
a[i]^=a[j];
a[j]^=a[i];
a[i]^=a[j];
}
//将数组a中的下标i到下标j之间的所有元素逆序倒置
void reverse(int a[],int i,int j)
{
for(; i<j; ++i,--j) {
swap(a,i,j);
}
}
void print(int a[],int length)
{
for(int i=0; i<length; ++i)
cout<<a[i]<<" ";
cout<<endl;
}
//求取全排列,打印结果
void combination(int a[],int length)
{
if(length<2) return;
bool end=false;
while(true) {
print(a,length);
int i,j;
//找到不符合趋势的元素的下标i
for(i=length-2; i>=0; --i) {
if(a[i]<a[i+1]) break;
else if(i==0) return;
}
for(j=length-1; j>i; --j) {
if(a[j]>a[i]) break;
}
swap(a,i,j);
reverse(a,i+1,length-1);
}
}
int main(int argc, char **argv)
{
int a[4] = {1, 2, 3, 4};
combination(a, sizeof(a) / sizeof(int));
return 0;
}
3:递归交换式(同2):
#include <iostream>
using namespace std;
template<typename T>
void permutation(T array[], int begin, int end)
{
int i;
if(begin == end){
for(i = 0; i <= end; ++i){
cout<<array[i]<<" ";
}
cout<<endl;
return;
} else {
//for循环遍历该排列中第一个位置的所有可能情况
for(i = begin; i <= end; ++i) {
swap(array[i], array[begin]);
permutation(array, begin + 1, end);
swap(array[i], array[begin]);
}
}
}
int main(int argc, char **argv)
{
int a[4] = {1, 2, 3, 4};
permutation(a, 0, sizeof(a) / sizeof(int) - 1);
return 0;
}
4:分分钟式(STL,NB!)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int n,num[1005];
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
num[i]=i;
do
{
for(int i=0;i<n;i++)printf("%d ",num[i]);
printf("\n");
}while(next_permutation(num,num+n));
return 0;
}
看到底,跪了,STL太NB了!功能强大!但要注意,STL有时不开优化的话效率比较低,应该谨慎使用,但毕竟用到全排列时一般是暴力,也就无所谓了~
部分代码引自:http://blog.csdn.net/e3399/article/details/7543861,在此表示感谢,虽然他不一定知道~