全排列
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
比如字符集{‘a’,‘b’,‘c’},共有3!种组合。
abc、bac、bca、acb、cab、cba。
我们可以发现后面五种情况都是可以通过第一种情况两两交换得到,通过分析我们可以推导出递归方式。
#include<iostream> #include<string> #include<string.h> using namespace std; int num=0; void SWAP(string & str,int x,int y){ char c=str[x]; str[x]=str[y]; str[y]=c; } void perm(string & str,int Begin,int End){ if(Begin==End){ cout<<++num<<' '<<str<<endl; }else{ for(int i=Begin;i<End;i++){ SWAP(str,Begin,i); //交换begin位置和 i 位置 perm(str,Begin+1,End); // begin位置后移,递归 SWAP(str,Begin,i); //换回来 } } } int main(){ string str; cin>>str; perm(str,0,str.length()); return 0; }
如果输出全排列需要按照字典序的顺序输出的话,我们可以把结果暂存在一个容器里面,比如用set保存,它会默认按字典序排列,最后输出结果,一定是按字典序的顺序输出。
set默认具有去重功能,如果不想去重,那么可以选择使用multiset保存,这样不会去重。
在c++中有更简单的方法使用全排列,algorithm头文件里面封装了next_permutation,prev_permutation函数,用来计算全排列。使用方法如下:(默认去重,默认字典序。)
next_permutation:对于当前的排列,如果在字典序中还存在下一个排列,返回真,并且将下一个排列赋予当前排列,如果不存在,就把当前排列进行递增排序。
prev_permutation对于当前的排列,如果在字典序中还存在前一个排列,返回真,并且将前一个排列赋予当前排列,如果不存在,就把当前排列进行递减排序。
#include<iostream> #include<algorithm> #include<stdio.h> using namespace std; char str[4]={'a','b','c','a'}; void pri(){ do{ printf("%c%c%c%c\n",str[0],str[1],str[2],str[3]); }while(next_permutation(str,str+4)); } int main(){ pri(); return 0; }