算法递归——集合的全排列问题

集合全排列问题

设集合 R={ r1,r2,r3 … r n},显然全排列的数目为 n!。
那么如何显示集合的所有全排列呢?
可以用递归的方式实现。

解题思路
如果集合有n个元素,那么就可以看作 n-1个元素全排列之后再加上 剩下的那个元素,因为是全排列,所以每一个元素都会剩下一次。(例如:
R={1,2,3}的全排列。
若 1 剩下,则 {2,3} 先进行排列,再与1结合,结果是 1 23,1 32。
若 2 剩下,则{1, 3}排列,与2结合,结果是 2 13, 2 31。
若 3,结果为 3 12 , 321。)

继续,n-1 个数的全排列又可以看作 n-2 个数的全排列,再与剩下的那个数结合。这就与刚刚的操作重复了,一层层的往下简化,直到最后,数列中只剩下了1个元素,递归就结束了。

来看具体实现

//定义一个数组,表示集合
//参数k为起始排列数的下标,m为结束下标。
void Perm(int list[], int k, int m)	
{
	if(k==m) 			//递归结束标志,起始下标=结束下标,代表集合内就一个数了。
	{
		for(int i=0;i<=m;i++)		
			cout<<list[i]<<" ";	//此时数组内的元素已经被交换好位置,一种排列可以输出。
		cout<<endl;
	}
	else
	{
		for(int j=k;j<=m;j++)	 //变量 j从起始k开始,到m结束,表示被剩下的那个数,
			{
				swap(list[k],list[j]);//刚开始k=j,就相当于1=1;1被剩下,j++后,变成2,相当于2被剩下,2在数组中代替1的位置.
				Perm(list,k+1,m);  //除了被剩下的,其余元素排列,相当于 23排列,再继续递归
				swap(list[k],list[j]);	//输出一种正确排列后需要把下标再换回。不然就乱套了
			}
	}
		
}

总结
这一种解题方法是通过递归算法改变数组中元素的位置然后输出。
利用递归,将n个元素步步分解:
n变成 剩下的任意一个数(n种情况)和n-1个数。

直到还剩下了最后一个元素,作为递归结束的标志。
在数组中位置的交替也是难点,直接上图好理解
在这里插入图片描述
剩余 1 的情况是第一列,
剩余 2 的情况是第二列

会发现,第一列与第二列的区别就在于,1 与 2 的位置不同,则要求第二列的排列时,只需让2 代替1的位置即可,其他列也是如此。

发布了36 篇原创文章 · 获赞 3 · 访问量 3531

猜你喜欢

转载自blog.csdn.net/qq_43628835/article/details/105555138