全排列问题(递归&非递归&STL函数)
问题描述:
打印输出1-9的所有全排序列,或者打印输出a-d的全排列。
思路分析:
将每个元素放到余下n-1个元素组成的队列最前方,然后对剩余元素进行全排列,依次递归下去。
比如:1 2 3 为例
首先将1放到最前方(跟第1个元素交换),然后后面2位再做全排,然后将1放回本来位置
结果 1 2 3; 1 3 2
其次将2放到最前方(跟第1个元素交换),然后后面2位再做全排,然后将2放回原处
结果 2 1 3; 2 3 1
。。。。。
C/C++递归实现:
#include<cstdio>
#include<iostream>
using namespace std;
void swap(int list[], int i, int j) //交换list中i和j位置的元素
{
int temp = list[i];
list[i] = list[j];
list[j] = temp;
}
void fun(int list[], int m, int n) //输出list中m到n的全排列
{
if(m==n)
{
for(int i=0; i<n; i++) //输出0-n的一个排列
{
printf("%d",list[i]);
}
printf("\n");
}
else
{
for(int i=m; i<n; i++)
{
swap(list,m,i); //把第i个和第一个(此时是m)交换
fun(list,m+1,n); //余下的继续递归
swap(list,m,i); //将第i个放回原处
}
}
}
int main()
{
int list[] = {1,2,3,4,5,6};
int length = sizeof(list)/sizeof(list[0]);
fun(list,0,length);
return 0;
}
C/C++非递归实现:(当输入中数字有重复数字时仍能正常工作,即不会有重复输出)
/*完全参考:http://blog.csdn.net/prstaxy/article/details/8147029*/
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
bool next(vector<int> &v)//注意是引用
{
int i;
for(i=v.size()-1;i>=1;i--)
{//从数组后面往前找到第一个比后面的数小的地方
if(v[i-1]<v[i])
break;
}
if(i==0)//整个数组都是逆序,说明是已是排列最后一个
return false;//没有下一个
else
{
int t=v[i-1],pos=i;
for(int j=i;j<v.size();j++)
{
if(v[j]>t && v[j]<=v[pos])//再往后找比v[i-1]大的数中最小的一个 //2014.10.1把<改成<=,否则输入有重复数字时会出现bug
pos=j;
}
v[i-1]=v[pos];
v[pos]=t;//交换
//sort(v.begin()+i,v.end());//从小到达排序
reverse(v.begin()+i,v.end());//此时正好逆序,只需反转即可从小到达排序
return true;//还有下一个
}
}
void printVctor(vector<int> v)
{
for(int i=0;i<v.size();++i)
cout<<v[i]<<" ";
cout<<endl;
}
int main()
{
int a[] = {1,2,3,4,5};
vector<int> v(a,a+5);
do
{
printVctor(v);
}while(next(v));
return 0;
}
C++ STL代码实现:
C++ STL中算法库中包含了计算排列组合关系的算法next_permutation、prev_permutation,用法如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int list[] = {1,2,3,4,5,6};
int length = sizeof(list)/sizeof(list[0]);
sort(list, list+length); /* 这个sort可以不用,因为{1,2,3,4}已经排好序*/
do /*注意这步,如果是while循环,则需要提前输出第一个次序*/
{
for(int i=0; i<length; i++)
{
printf("%d",list[i]);
}
printf("\n");
}while(next_permutation(list,list+length));
//while(prev_permutation(list,list+length));//求上一个排列数,初始数组用逆序来调用可以输出全排列
return 0;
}
参考链接:
next_permutation(全排列算法) http://blog.csdn.net/c18219227162/article/details/50301513
上面这个链接开始介绍了排列组合是如何区分前一个后一个的,也就是如何排序的; 最后还包含一个 “直接算出集合{1, 2, ..., m}的第n个排列” 的代码实现
http://blog.csdn.net/prstaxy/article/details/8147029
http://blog.csdn.net/knisinf/article/details/48048011