全排列函数、组合函数
1
1、求一个全排列函数:如p([1,2,3])输出:
[123],[132],[213],[231],[321],[312].
2、求一个组合函数如p([1,2,3])输出:
[1],[2],[3],[1,2],[2,3],[1,3],[1,2,3]
这两问可以用伪代码。
void swap(int *a, int *b) //交换函数 {int tmp;tmp =*a;*a=*b;*b=tmp; }
以为很简单,手写全排序第一遍就错了。
func1( a[], n, m)if(m>n-1) return; endprint(a);for(i=m+1 to n-1)swap(a[m], a[i]);func1(a, n, m+1);swap(a[m], a[i]);end end 调用:func1(a, n, 0)
发现以a[0]开头的只有一组,其他可以满足,因为i=m+1。func1的理解就是输出a,并将a[m]分别与a[m+1]..a[n]交换后的后n-m-1个元素的排列组合。当调用了func1(a, n, 0)时,以a[0]开头的只有一组。改为for(i=m to n)可以吗?
No!这时候,却多出很多。由于m>n-1才是终止条件。即要进入n-1层,每层有n-m+1个分支,于而每进入一层就会print(a),这样就会输出的次数不等于n!了(一般情况下)
纠结了n久之后,再改,应该当m=n-1时才输出。Bingo!
1 func1( a[], n, m) 2 if(m==n-1) 3 print(a); 4 return; 5 end 6 for(i=m+1 to n-1) 7 swap(a[m], a[i]); 8 func1(a, n, m+1); 9 swap(a[m], a[i]); 10 end 11 end 12 13 调用:func1(a, n, 0)
可是结果却和题目的不完全一致。因为是输出的位置的先后问题。换成尾递归即可。
1 void func1(int a[], int m, int n) 2 { 3 for (int j=m; j<n; j++) 4 { 5 swap(&a[m], &a[j]); 6 func1(a, m+1, n); 7 swap(&a[m], &a[j]); 8 } 9 if (m==n-1) 10 { 11 for (int i=0; i<n; i++) 12 { 13 cout<<a[i]<<" "; 14 } 15 cout<<endl; 16 return; 17 } 18 }
简单的题目也不见得简单啊~(其实个人水平问题。。。)
2、只考虑有最大有32个数的情况:
1 void func2(int a[], int n) 2 { 3 int cnt=1; 4 5 if (n>32 || n<=0) 6 { 7 return; 8 } 9 cnt = cnt<<n; 10 11 unsigned int tmp; 12 for (unsigned int i=0; i<=cnt; i++) 13 { 14 tmp = 1; 15 for (int j=0; j<n; j++) 16 { 17 if (i & tmp) 18 { 19 cout<<a[j]<< " "; 20 } 21 tmp = tmp<<1; 22 } 23 cout<<endl; 24 } 25 }
总结:
常用的排列组合算法,包括全排列算法,全组合算法,m个数选n个组合算法等。
2. 排列算法
常见的排列算法有:
(A)字典序法
(B)递增进位制数法
(C)递减进位制数法
(D)邻位对换法
(E)递归法
介绍常用的两种:
(1) 字典序法
对给定的字符集中的字符规定了一个先后关系,在此基础上按照顺序依次产生每个排列。
[例]字符集{1,2,3},较小的数字较先,这样按字典序生成的全排列是:123,132,213,231,312,321。
生成给定全排列的下一个排列 所谓一个的下一个就是这一个与下一个之间没有字典顺序中相邻的字符串。这就要求这一个与下一个有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。
算法思想:
设P是[1,n]的一个全排列。
P=P1P2…Pn=P1P2…Pj-1PjPj+1…Pk-1PkPk+1…Pn , j=max{i|Pi<Pi+1}, k=max{i|Pi>Pj} ,对换Pj,Pk,将Pj+1…Pk-1PjPk+1…Pn翻转, P’= P1P2…Pj-1PkPn…Pk+1PjPk-1…Pj+1即P的下一个
例子:839647521的下一个排列.
从最右开始,找到第一个比右边小的数字4(因为4<7,而7>5>2>1),再从最右开始,找到4右边比4大的数字5(因为4>2>1而4<5),交换4、5,此时5右边为7421,倒置为1247,即得下一个排列:839651247.用此方法写出全排列的非递归算法如下
该方法支持数据重复,且在C++ STL中被采用。
(2) 递归法
设一组数p = {r1, r2, r3, … ,rn}, 全排列为perm(p),pn = p – {rn}。则perm(p) = r1perm(p1), r2perm(p2), r3perm(p3), … , rnperm(pn)。当n = 1时perm(p} = r1。
如:求{1, 2, 3, 4, 5}的全排列
1、首先看最后两个数4, 5。 它们的全排列为4 5和5 4, 即以4开头的5的全排列和以5开头的4的全排列。
由于一个数的全排列就是其本身,从而得到以上结果。
2、再看后三个数3, 4, 5。它们的全排列为3 4 5、3 5 4、 4 3 5、 4 5 3、 5 3 4、 5 4 3 六组数。
即以3开头的和4,5的全排列的组合、以4开头的和3,5的全排列的组合和以5开头的和3,4的全排列的组合.
以上的算法1的即是使用这个方法。
3组合算法
3.1 全组合
在此介绍二进制转化法,即,将每个组合与一个二进制数对应起来,枚举二进制的同时,枚举每个组合。如字符串:abcde
00000 <– –> null
00001<– –> e
00010 <– –> d
… …
11111 <– –> abcde
以上的算法2的即是使用这个方法。
3.2 从n中选m个数
(1) 递归
a. 首先从n个数中选取编号最大的数,然后在剩下的n-1个数里面选取m-1个数,直到从n-(m-1)个数中选取1个数为止。
b. 从n个数中选取编号次小的一个数,继续执行1步,直到当前可选编号最大的数为m。
下面是递归方法的实现:
1 /// 求从数组a[1..n]中任选m个元素的所有组合。 2 3 /// a[1..n]表示候选集,n为候选集大小,n>=m>0。 4 5 /// b[1..M]用来存储当前组合中的元素(这里存储的是元素下标), 6 7 /// 常量M表示满足条件的一个组合中元素的个数,M=m,这两个参数仅用来输出结果。 8 9 void combine( int a[], int n, int m, int b[], const int M ) 10 11 { 12 13 for(int i=n; i>=m; i--) // 注意这里的循环范围 14 15 { 16 17 b[m-1] = i - 1; 18 19 if (m > 1) 20 21 combine(a,i-1,m-1,b,M); 22 23 else // m == 1, 输出一个组合 24 25 { 26 27 for(int j=M-1; j>=0; j--) 28 29 cout << a[b[j]] << " "; 30 31 cout << endl; 32 33 } 34 35 } 36 37 }
1 void func19(int m, int n) //非递归 2 { 3 int *arr; 4 int i, pos; 5 6 if (m<n) 7 { 8 return ; 9 } 10 11 arr = new int[n]; 12 13 for (i=0; i<n; ++i) 14 { 15 arr[i] = i+1; 16 } 17 18 for (i=0; i<n; ++i) 19 { 20 cout<<arr[i]<<" "; 21 } 22 cout<<endl; 23 24 pos = n-1; 25 while(1) 26 { 27 if (arr[n-1] == m ) 28 { 29 pos--; 30 } 31 else 32 { 33 pos = n-1; 34 } 35 36 arr[pos] ++; 37 38 for (i=pos+1; i<n; i++) 39 { 40 arr[i] = arr[i-1]+1; 41 } 42 43 for (i=0; i<n; ++i) 44 { 45 cout<<arr[i]<<" "; 46 } 47 cout<<endl; 48 49 if (arr[0] == m-n+1) 50 { 51 break; 52 } 53 } 54 }
(2) 01转换法
本程序的思路是开一个数组,其下标表示1到n个数,数组元素的值为1表示其代表的数被选中,为0则没选中。
首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。
然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为“01”组合,同时将其左边的所有“1”全部移动到数组的最左端。
当第一个“1”移动到数组的n-m的位置,即n个“1”全部移动到最右端时,就得到了最后一个组合。
例如求5中选3的组合:
1 1 1 0 0 //1,2,31 1 0 1 0 //1,2,41 0 1 1 0 //1,3,40 1 1 1 0 //2,3,41 1 0 0 1 //1,2,51 0 1 0 1 //1,3,50 1 1 0 1 //2,3,51 0 0 1 1 //1,4,50 1 0 1 1 //2,4,50 0 1 1 1 //3,4,5
4. 参考资料
(1) http://www.cnblogs.com/nokiaguy/archive/2008/05/11/1191914.html
(2) http://comic.sjtu.edu.cn/thucs/GD_jsj_025y/text/chapter01/sec05/default.htm
(3) http://blog.csdn.net/sharpdew/archive/2006/05/25/755074.aspx
(4) http://xiaomage.blog.51cto.com/293990/74094
以上总结源于:董的博客
转载于:https://www.cnblogs.com/legendmaner/archive/2013/03/19/2969115.html
全排列函数、组合函数相关推荐
- 函数组合的 N 种模式
随着以函数即服务(Function as a Service)为代表的无服务器计算(Serverless)的广泛使用,很多用户遇到了涉及多个函数的场景,需要组合多个函数来共同完成一个业务目标,这正是微 ...
- 基于函数工作流的函数组合
基于函数工作流的函数组合 函数工作流(Function Flow,简称 FnF)是一个用来协调多个分布式任务执行的全托管 Serverless 云服务,简化了开发和运行业务流程所需要的任务协调.状态管 ...
- JAVASCRIPT函数组合:有什么大不了的?
一些人会说,函数组合是某种神圣的真理.一个你应该沉思时卑微地跪下并上香的神圣原则.但函数组合其实并不复杂.不过你是否意识到,你可能一直在使用它.那么为什么函数式编程程序员会对此烦恼呢?它有什么大不了的 ...
- 【JavaScript进阶之旅 函数式编程篇 第三十四章】函数组合、结合律、pointfree、使用案例
文章目录 一.函数组合 1.左倾(高阶函数的左倾) 2. 组合多个函数 方法一(使用while) 方法二:优化组合函数(使用reduceRight) 二.结合律 三.pointfree 一.函数组合 ...
- JavaScript函数式编程(纯函数、柯里化以及组合函数)
JavaScript函数式编程(纯函数.柯里化以及组合函数) 目录 JavaScript函数式编程(纯函数.柯里化以及组合函数) 前言 1.纯函数 1.1.纯函数的概念 1.2.副作用 1.3.纯函数 ...
- python中全组合函数(combinations)与全排列函数(permutations)
最近写代码时遇到排列组合问题,发现python中的itertools库用起来比较方便.itertools库中的permutations函数可以输出可迭代对象的全排列情况,而combinations函数 ...
- python中全组合函数(combinations)与全排列函数(permutations)的介绍与参数说明
概要:在平常的编程过程中,往往需要面对排列组合的应用情况,而每次自己编写相应的函数会耗费较多的时间,而python中的itertools库就为我们解决了这个小问题.itertools库中的permut ...
- Python排列函数和组合函数
排序函数:permutations() 缺点:不能按照顺序输出下一个更大的排列 from itertools import * s=['a','b','c'] for i in permutation ...
- operate函数_跟着 redux 学 compose组合函数
▲ 点击上方蓝字关注我 ▲ 把你的心 我的心串一串 串一株幸运草 串一个同心圆 文 / 景朝霞 来源公号 / 朝霞的光影笔记 ID / zhaoxiajingjing 目录0 / 热热身1 / red ...
最新文章
- 公司-弹出页回调之后加载页面
- php和python对比-通过PHP与Python代码对比浅析语法差异
- 实操将TensorFlow模型部署成Docker服务化
- javascript等号判断相等流程
- C#里面SQLite读取数据的操作
- 缺陷定位 | 分析推理定位BUG案例(三)
- 原版英文书籍《Linux命令行》阅读记录7 | 一些键盘按键技巧
- unity3D---鼠标、键盘输入
- activiti(7.0) 组任务流程CandidateUsers
- Linux 服务器性能出问题,排查下这些参数指标
- PHP文件操作-读取数据库文件路径复制到另一个目录
- VMware安装Ubuntu配置NAT模式下静态IP,解决访问外网问题
- 在tomcat下配置jdbc连接池
- linux镜像迅雷下载,【转】红帽 Red Hat Linux相关产品iso镜像下载【迅雷快传】【百度云】【更新7.1】...
- 截止到 2019 年 6 月 14 日在 LeetCode 中文版上写的题解
- oracle汉字转拼音
- 基于臻图ZTMAP 3DGIS平台打造线上线下融合的智慧展览中心
- 太阳能供电锂电充电IC
- 2022国内TMS运输管理系统排行榜
- Linux中的setenv与export
热门文章
- win7系统如何访问xp系统的服务器,WIN7系统怎么让XP系统访问呢
- python列表中随机两个_随机化两个列表并在python中维护顺序
- 判别分析分为r型和q型吗_SPSS聚类和判别分析参考.ppt
- 64位 regsrv win10_Win10 64位安装个人版SQL2000图文教程
- python flask html模板,python flask web开发实战 Jinja2模板
- python 数据处理----读取txt 一列数据写入excel 文件
- 串口服务器介绍及产品特点详解
- 光模块的正确安装方法和使用须知
- 【渝粤教育】国家开放大学2019年春季 2712园艺基础 参考试题
- LoRa、Sigfox和NB-IoT在物联网趋势中谁是你的最佳拍档?