全排列

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;
}

测试结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值