全排列及相关扩展算法(一)——基础的回溯递归实现全排列算法
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.运行截图
注:函数调用意为:从第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
全排列及相关扩展算法(一)——基础的回溯递归实现全排列算法相关推荐
- 全排列及相关扩展算法(七)——组合数的字典序(另含全章代码整理)
1.引入概念:要列出一个集合{1,2,3,4}的所有子集是很容易的,我们可以按照二进制数的顺序,0000,0001,0010,0011,0100,0101,0110,0111......来表示我们要取 ...
- 全排列及相关扩展算法(六)——全排列最蛋疼的算法:邻位对换法
1.引入原因:在此之前我们实现全排列本质上都是采用单向交换的思路,当交换到末端便要回溯至上一层面,如果我们采用双向的交换,便可以不断地交换下去,于是产生了邻位对换法.邻位对换法在找下一个排列的方法上在 ...
- 全排列邻位对换法c语言算法,全排列及相关扩展算法(六)——全排列最蛋疼的算法:邻位对换法...
1.引入原因:在此之前我们实现全排列本质上都是采用单向交换的思路,当交换到末端便要回溯至上一层面,如果我们采用双向的交换,便可以不断地交换下去,于是产生了邻位对换法.邻位对换法在找下一个排列的方法上在 ...
- 全排列及相关扩展算法(五)——递增(递减)进位制数求原排列算法
1.引入原因:通过上一章我们意识到通过原始中介数求原排列并不是那么的方便,于是我们延伸出几种新的中介数算法来方便计算原排列. 2.递增进位制数法:递增进位制是指数字的进制随着数字位置的不同递增,一般的 ...
- 全排列及相关扩展算法(二)——求字典序下一组排列及全排列算法
1.字典序排列的定义:为了便于理解,以数字为例,对于数字1.2.3......n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的.例如对于5个数字的排列 12354和12345,排 ...
- 全排列及相关扩展算法(三)——利用中介数求排列在字典序排位算法
1.中介数的定义及作用:很多时候,我们要通过一个排列得出它的字典序中的位置(序号),比如1234567应该排在第0位(开始位),1234576应该排在第1位,7654321排在第7!-1=5039位. ...
- 全排列及相关扩展算法(四)——原始中介数通过逆推求原排列算法
1.中介数逆推原排列:上一章我们讲到了中介数,通过一个排列可以很方便地求数它的中介数,通过中介数也可以很方便地求出排位序号.但是通过中介数逆推原排列就不是那么容易了.因为我们每求一位数,都需要对比其前 ...
- 算法作业04(回溯与分支界限算法)(骑士游历与行列变换问题)
1.骑士游历问题 问题描述: 在国际象棋的棋盘(8行×8列)上放置一个马,按照"马走日字"的规则,马要遍历棋盘,即到达棋盘上的每一格,并且每格只到达一次.若给定起始位置(x0,y0 ...
- 【Java -- 算法】分治算法、动态规划、回溯法、贪心算法
前言 一句话理解四种算法思想 分治:分而治之,先解决子问题,再将子问题的解合并求出原问题. 贪心:一条路走到黑,选择当下局部最优的路线,没有后悔药. 回溯:一条路走到黑,手握后悔药,可以无数次重来.( ...
最新文章
- 腾讯阿里是否开始走向没落,用新互联网大脑模型分析
- c语言贪吃蛇编写分析,刚学C语言,想写一个贪吃蛇的代码
- 测试使用wiz来发布blog
- matlab求傅里叶级数展开式_连续时间的傅里叶级数
- mysql bean分页查询_javabean 来实现 MySQL 的分页
- java maven jar 打包_使用Maven打包可运行jar和javaagent.jar的区别
- vscode中如何拉取git代码_工具 | 手把手教你在VSCode中使用Git
- 用开源组件jcaptcha做jsp彩色验证码
- abb变频器dp适配器说明书_PROFIBUS-DP与ABB变频器之间通讯设置步骤
- VUE 中使用 Element 时间控件(简单上手)
- linux下u盘不识别问题,linux u盘不识别解决办法
- R语言——自定义函数求置信区间
- c# 中控 触摸精灵_触摸精灵脚本编辑器
- linux下格式化SD卡
- [Vue][transition]Vue中实现类似JQuery中slideUp slideDown的滑动显示隐藏过渡动画效果
- JSP设置Excel表格换行_Excel中快速将阿拉伯数字转化为大写文字的妙招
- AjaxPro的AJAX示例
- jsp网上商店网上书店
- 通过dockerfile构建jar包镜像
- 微软亚洲研究院推出“人立方”人物关系搜索
热门文章
- 智能实验室服务器,阿里巴巴机器智能实验室线下智能团队三年工作总结
- MFC工程按USB插口显示所有USB设备及插口(包括安卓)
- STL之双向循环链表(List)的内部关系
- python如何查看源码_查看“Python-2020-fall”的源代码
- InceptionNet与mobileNet
- [Matlab] PDETool 的 Set Formula 的元素排列顺序会影响 Boundary 的判定
- 合肥注册公司(各区注册地点说明)
- CSS鼠标悬停隐藏展开简介特效
- adb隐藏状态栏图标_[应用]华为手机怎么设置隐藏状态栏上的图标
- 仿小说蓝色小说网站导航引流网站源码 带手机版