1. 全排列的递归实现-1
数据结构上都学习过八皇后的问题,用的书回溯法来实现的,其本质是一个先序遍历的树的过程,借助此思想来实现一个全排列的产生过程是易于理解的。代码如下:
//全排列的实现
int b_inner[20];
int m;
/*
*回溯法思想,递归的实现
*/
bool f(int c,int k){
for(int i=0;i<k;i++){
if(b_inner[i]==c)
return false;
}
return true;
}
void getPermutation(int n){
if(n==0){
for(int c=0;c<m;c++){
cout<<" "<<b_inner[c];
}
cout<<endl;
return;
}
for(int i=0;i<m;i++){
if(f(i+1,m-n)){////若b中不存在a中的这个元素
b_inner[m-n]=i+1;
getPermutation(n-1);
}
}
}
测试代码:
int _tmain(int argc, _TCHAR* argv[])
{
m=4;
getPermutation(4);
return 0;
}
结果如图:
2. 全排列的递归实现-2
为方便起见,用123来示例下。123的全排列有123、132、213、231、312、321这六种。首先考虑213和321这二个数是如何得出的。显然这二个都是123中的1与后面两数交换得到的。然后可以将123的第二个数和每三个数交换得到132。同理可以根据213和321来得231和312。因此可以知道——全排列就是从第一个数字起每个数分别与它后面的数字交换。
代码如下:
/*
*递归的另一种实现,使用的是交换法
*/
void exchange(int a,int b){
int c=b_inner[a];
b_inner[a]=b_inner[b];
b_inner[b]=c;
}
void getPermutation_1(int n){
if(n==1){//输出来
for(int c=0;c<m;c++){
cout<<" "<<b_inner[c];
}
cout<<endl;
return;
}else{
for(int i=m-n;i<m;i++){
exchange(m-n,i);
getPermutation_1(n-1);
exchange(m-n,i);
}
}
}
测试代码:
int _tmain(int argc, _TCHAR* argv[])
{
m=4;
for(int i=0;i<m;i++){
b_inner[i]=i+1;
}
getPermutation_1(4);
return 0;
}
结果和上面的是一样的。略去。
3.非递归的实现,这是比较难点的了。不过在组合数学》 Richard A. Brualdi著的 Chapter 4 Generating Permutations and Combinations中有详细描述,读者应该看看,就会很好的理解怎么用非递归的方法实现的。这还是很有技巧性的方法。
代码如下:
/*
*algorithm for generating the permutations of {1,2,...n}
*begin with (1,0)(2,0)(...)(n,0)
*while there exists a mobile integer ,do the following:
*(1)find the largest mobile integer m
*(2)switch m and the adjacent integer to which its arrow points
*(3)switch the direction of all the arrows above integers p with p>m
*详细内容参见《组合数学》 Richard A. Brualdi著。 Chapter 4 Generating Permutations and Combinations
*/
struct Elem{
int key;
int flag;//0--left,1--right
};
Elem tElem[10];//用10进行测试
int has_mobile(int m){//没有mobile元素时返回-1,否则返回最大mobile值的下标值,这是一个遍历操作
int k=-1;
Elem result;
result.key=-1;
Elem temp;
for(int i=0;i<m;i++){
temp=tElem[i];
if(i==0){
if(temp.flag==1&&tElem[i+1].key<tElem[i].key)
{
result.flag=tElem[i].flag;
result.key=tElem[i].key;
k=i;
}
}else if(i==m-1){
if(temp.flag==0&&tElem[i-1].key<tElem[i].key&&tElem[i].key>result.key)
{
result.flag=tElem[i].flag;
result.key=tElem[i].key;
k=i;
}
}else{
if(temp.flag==0){
if(tElem[i-1].key<temp.key&&temp.key>result.key){
result.flag=temp.flag;
result.key=temp.key;
k=i;
}
}else if(temp.flag==1){
if(tElem[i+1].key<temp.key&&temp.key>result.key){
result.flag=temp.flag;
result.key=temp.key;
k=i;
}
}
}
}
return k;
}
void swap (int a,int b){
Elem temp;
temp.key=tElem[b].key;
temp.flag=tElem[b].flag;
tElem[b].flag=tElem[a].flag;
tElem[b].key=tElem[a].key;
tElem[a].flag=temp.flag;
tElem[a].key=temp.key;
}
void exchangeFlag(int key,int n){
for(int i=0;i<n;i++){
if(tElem[i].key>key)
tElem[i].flag=1-tElem[i].flag;
}
}
void outPut(int m){
for(int i=0;i<m;i++){
cout<<" "<<tElem[i].key;
if(tElem[i].flag==0){
cout<<"<--";
}else{
cout<<"-->";
}
}
cout<<endl;
}
void getPermutation_2(int n){
int k=has_mobile(n);
while(k>=0){
Elem temp=tElem[k];
int tmp_Key=temp.key;
if (temp.flag==0){//交换左边的
swap (k-1,k);
}else if(temp.flag==1){//交换右边的
swap (k,k+1);
}
//进行第三个步骤
exchangeFlag(temp.key, n);
outPut(n);
k=has_mobile(n);
}
}
测试代码:
int _tmain(int argc, _TCHAR* argv[])
{
for(int i=0;i<4;i++){
tElem[i].flag=0;
tElem[i].key=i+1;
}
outPut(4);
getPermutation_2(4);
return 0;
}
测试结果如下: