为了账号安全,请及时绑定邮箱和手机立即绑定

全排列及相关扩展算法(一)——基础的回溯递归实现全排列算法

1.全排列的定义和公式: 从n个数中选取m(m<=n)个数按照一定的顺序进行排成一个列,叫作从n个元素中取m个元素的一个排列。由排列的定义,显然不同的顺序是一个不同的排列。从n个元素中取m个元素的所有排列的个数,称为排列数。从n个元素取出n个元素的一个排列,称为一个全排列。全排列的排列数公式为n!,通过乘法原理可以得到。

2.时间复杂度: n个数(字符、对象)的全排列一共有n!种,所以全排列算法至少时O(n!)的。如果要对全排列进行输出,那么输出的时间要O(n*n!),因为每一个排列都有n个数据。所以实际上,全排列算法对大型的数据是无法处理的,而一般情况下也不会要求我们去遍历一个大型数据的全排列。

3.全排列算法解决思路:假设现有1 2 3 三个数,我们构造全排列的方式为:先确定第一位1,然后可选(2,3)(3,2)作为后序的排列组合,这样以1作为首位的全排列就有(1,2,3)(1,3,2)两种,然后再以2作为第一位,从而构造出(2,1,3)(2,3,1).最后是(3,1,2)(3,2,1)。即求n个数的全排列=先枚举确立一个数,然后求n-1的全排列。这与我们常见的回溯递归法基本一样。当所有的位数都确定完毕,即成为一组完整的排列数,也就是递归的出口。

4.全排列算法代码:


void Permutation(int A[], int m, int n){	if (m == n)	{		Print(A, n);		Count++;	}	else	{		for (int i = m; i < n; i++)		{			Swap(A[m], A[i]);			Permutation(A, m + 1, n);			Swap(A[m], A[i]);		}	}}


当m==n即所有位数都确定,即为一组完整的排列数,否则枚举确定第m位数(使第m位依次与后面位数交换),递归返回后再回溯还原。


注:Print函数功能为输出A数组前n位,Swap函数为交换两个数,Count为全局变量,记录排列数


void Swap(int &a, int &b){	a == b ? 0 : a ^= b ^= a ^= b;}void Print(int A[], int n){	for (int i = 0; i < n; i++)	{		printf("%d%c", A[i], i == n - 1 ? '\n' : ' ');	}}


外部调用:



int main(){	int A[] = { 1,2,3,4 };	int n = sizeof(A) / sizeof(A[0]);	Permutation(A, 0, n);	printf("%d\n", Count);	system("pause");	return 0;}


5.时间复杂度


此算法可以列出从A数组中第m个元素到第n个元素的所有排列,注意m,n可以在任意位置。算法的复杂度在于for循环和递归,最大的for是n,递归为n-1所以为O(n*n-1*n-2*...1)=O(n!)


6.运行截图

https://img1.sycdn.imooc.com//5b4dd81d000109d805680302.jpg




https://img1.sycdn.imooc.com//5b4dd8240001b91005590212.jpg

注:函数调用意为:从第2位到第4位(不包括)的全排列,故收影响的排列只有(1,2,3,4,5)(1,2,4,3,5)

由于我们的Print函数是从0位输出到n位的,所以只打印了0-3位,此样例只是辅助说明Permutation函数中m和n参数的作用。


7.参考文档

https://wenku.baidu.com/view/8c79a2facc17552706220880.html


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消