全排列生成算法
全排列的几种算法

全排列的⼏种算法全排列,我们⾼中时就学过,数学上很简单,可是⽤计算机的算法实现还是有点味道的,今天我将我碰到的⼏种算法如数奉上,欢迎交流!第⼀种:递归最常见的也是最好理解的⽅法:简单点:⽐如"a" ,"b","c"全排列,可以看做事"a" +"b","c"的全排列及"b"+ "a","c"的全排列及"c" + "a","b"的全排列也就是说,遍历原数组中的每个元素,让剩余的元素全排列,这样就找到规律了。
代码如下:public static void main(String[] args) {char buf[]={'a','b','c','d'};perm(buf,0,buf.length-1);}public static void perm(char[] buf,int start,int end){if(start==end){//当只要求对数组中⼀个字母进⾏全排列时,只要就按该数组输出即可(特殊情况)for(int i=0;i<=end;i++){System.out.print(buf[i]);}System.out.println();}else{//多个字母全排列(普遍情况)for(int i=start;i<=end;i++){//(让指针start分别指向每⼀个数)char temp=buf[start];//交换数组第⼀个元素与后续的元素buf[start]=buf[i];buf[i]=temp;perm(buf,start+1,end);//后续元素递归全排列temp=buf[start];//将交换后的数组还原buf[start]=buf[i];buf[i]=temp;}}}第⼆中⽅法:也是递归,但是和第⼀种有所区别,算法:将数据分为两部分,递归将数据从左侧移右侧实现全排列⽐较抽象,如list abcd,遍历每⼀个数,将每个数放到⼀个新的list中,并将该元素从原list删除,然后将剩下的元素继续遍历每个元素继续放到新的list ⾥,这样,当list的长度为原list长度,或者原list长度为0时打印结果!下⾯是简单的⽰意图:// abcd//bcd a//cd ab//d abc//abcd//c abd//abdc//bd ac//d acb//acbd//b acd//acdb//bc ad ...//acd b ...//abd c ...//abc d ...源代码如下:private static void sort(List datas, List target) {//System.out.println("size="+datas.size());if (datas.size()==0) {for (Object obj : target)System.out.print(obj+" ");System.out.print(" ");return;}for (int i = 0; i < datas.size(); i++) {List newDatas = new ArrayList(datas);List newTarget = new ArrayList(target);newTarget.add(newDatas.get(i));newDatas.remove(i);sort(newDatas, newTarget);}}public static void main(String[] args) {List list = new ArrayList();for(int i=0;i<5;i++){list.add(i+1);}sort(list, new ArrayList());}第三种⽅法:⾮递归直接上代码:public static void main(String[] args) {int[] arr = new int[]{1,2,3,4,5,6};for(int i :arr){System.out.print(i + " ");}System.out.println();int totalnum = 1;while(NextNumber(arr,arr.length)){for(int i :arr){System.out.print(i + " ");}System.out.println();totalnum ++;}System.out.println("Total Num: " + totalnum);}private static Boolean NextNumber(int[] arr, int n){//数组最后⼀个元素位置int lastIndex = n-1;//从右向左确定第⼀个数字(前⾯的数字⽐它⼩)int firstIndex = lastIndex;for(;arr[firstIndex-1]>arr[firstIndex];firstIndex--){if(firstIndex == 1){//已经轮询完毕,此数已经是最⼤的那个数return false;}}//从右向左确定⼀个交换数(此数⽐arr[firstIndex]⼩且⽐arr[firstIndex-1]⼤)int swapIndex = lastIndex;for(;swapIndex > firstIndex;swapIndex--){if(arr[swapIndex] < arr[firstIndex] && arr[swapIndex] > arr[firstIndex-1]){break;}}//交换数字swap(arr,firstIndex-1,swapIndex);//将firstIndex右边的数字排序for(;firstIndex < lastIndex;firstIndex++,lastIndex--){if(arr[firstIndex] > arr[lastIndex]){swap(arr,firstIndex,lastIndex);}}return true;}private static void swap(int[] arr,int i, int j){int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}如果此⽂对你有帮助,请留个⾔,新⼈需要打架的⽀持和⿎励!。
全排列生成算法

全排列的生成算法对于给左的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。
字典序法按照字典序求下一个排列的算法广例字符集{1,2,3},较小的数字较先,这样按字典序生成的全排列是:123,132,213,231,312,321o注意一个全排列可看做一个字符串,字符串可有前缀、后缀/生成给泄全排列的下一个排列所谓一个全排列的下一个排列就是这一个排列与下一个排列之间没有其他的排列。
这就要求这一个排列与下一个排列有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。
广例839647521是1—9的排列。
1—9的排列最前而的是123456789,最后而的是987654321,从右向左扫描若都是增的,就到了987654321,也就没有下一个了。
否则找出第一次出现下降的位置。
算法:由P1P2...Pn生成的下一个排列的算法如下:1求j=max{j| Pj-I<pj}2.求|=max{k| Pi-1<Pk }3.交换Pi-1与PI得到P1P2...PI-1 (P i....Pn ),将红色部分顺序逆转,得到结果.例求839647521的下一个排列1.确定i,从左到右两两比较找出后一个数比前一个大的组合,在这里有39 47,然后i 取这些组中最到的位宜号(不是最大的数)在这两组数中7的位置号最大为6,所以i=62.确立I.找岀在i (包括i)后面的所有比i前面那一位大的数的最大的位置号,在此例中7, 5都满足要求,则选5, 5的位置号为7,所以1=73.先将4和5交换,然后将5后的四位数倒转得到结果8396574213 839651247以上算法是在数论课上老师给岀的关于字典序全排列的生成算法,以前也经常要用到全排列生成算法来生成一个全排列对所有的情况进行测试,每次都是现到网上找一个算法,然后直接copy代码,修改一下和自己的程序兼容就行了,也不看是怎么来的,不是我不想看,实在是说的很抽象,那一大堆公式来吓人,一个实例都不给,更有甚者连算法都没有,只是在那里说,想看都看不懂,也没那个耐心取理解那些人写出来的那种让人无法忍受的解释。
全排列问题的解析

1.5全排列的生成算法全排列的生成算法就是对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。
这里介绍全排列算法四种:(A)字典序法(B)递增进位制数法(C)递减进位制数法(D)邻位对换法1.5.1字典序法对给定的字符集中的字符规定了一个先后关系,在此基础上规定两个全排列的先后是从左到右逐个比较对应的字符的先后。
[例]字符集{1,2,3},较小的数字较先,这样按字典序生成的全排列是:123,132,213,231,312,321。
[注意] 一个全排列可看做一个字符串,字符串可有前缀、后缀。
1)生成给定全排列的下一个排列所谓一个的下一个就是这一个与下一个之间没有其他的。
这就要求这一个与下一个有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。
[例]839647521是1--9的排列。
1—9的排列最前面的是123456789,最后面的是987654321,从右向左扫描若都是增的,就到了987654321,也就没有下一个了。
否则找出第一次出现下降的位置。
/1.5.2递增进位制数法1)由排列求中介数在字典序法中,中介数的各位是由排列数的位决定的.中介数位的下标与排列的位的下标一致。
在递增进位制数法中,中介数的各位是由排列中的数字决定的。
即中介数中各位的下标与排列中的数字(2—n)一致。
可看出n-1位的进位链。
右端位逢2进1,右起第2位逢3进1,…,右起第i位逢i+1进1,i=1,2,…,n-1. 这样的中介数我们称为递增进位制数。
上面是由中介数求排列。
由序号(十进制数)求中介数(递增进位制数)如下:m=m1,0≤m≤n!-1m1=2m2+kn-1,0≤kn-1≤1m2=3m3+kn-2,0≤kn-2≤2……………mn-2=(n-1)mn-1+k2,0≤k2≤n-2mn-1=k1,0≤k1≤n-1p1p2…pn←→(k1k2…kn-1)↑←→m在字典序法中由中介数求排列比较麻烦,我们可以通过另外定义递增进位制数加以改进。
全排列的生成算法

全排列的生成算法全排列的生成算法就是对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。
任何n 个字符集的排列都可以与1~n的n个数字的排列一一对应,因此在此就以n个数字的排列为例说明排列的生成法。
n个字符的全体排列之间存在一个确定的线性顺序关系。
所有的排列中除最后一个排列外,都有一个后继;除第一个排列外,都有一个前驱。
每个排列的后继都可以从它的前驱经过最少的变化而得到,全排列的生成算法就是从第一个排列开始逐个生成所有的排列的方法。
全排列的生成法通常有以下几种:字典序法递增进位数制法递减进位数制法邻位交换法递归类算法1.字典序法字典序法中,对于数字1、2、3......n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。
例如对于5个数字的排列12354和12345,排列12345在前,排列12354在后。
按照这样的规定,5个数字的所有的排列中最前面的是12345,最后面的是54321。
字典序算法如下:设P是1~n的一个全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn1)从排列的右端开始,找出第一个比右边数字小的数字的序号j(j从左端开始计算),即j=max{i|pi<pi+1}2)在pj的右边的数字中,找出所有比pj大的数中最小的数字pk,即 k=max{i|pi>pj}(右边的数从右至左是递增的,因此k是所有大于pj的数字中序号最大者)3)对换pi,pk4)再将pj+1......pk-1pkpk+1pn倒转得到排列p’’=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,这就是排列p的下一个下一个排列。
例如839647521是数字1~9的一个排列。
从它生成下一个排列的步骤如下:自右至左找出排列中第一个比右边数字小的数字4 839647521在该数字后的数字中找出比4大的数中最小的一个5 839647521将5与4交换 839657421将7421倒转 839651247所以839647521的下一个排列是839651247。
组合数学 第一章 排列组合5全排列的生成算法合

1.5.2字典序法
[例] 求839647521的下一个排列
找出比右边数字小的标号最大的数4
8397655 72124124517
44><<2157
大小为于于后44的的缀用用橙绿色 色表 表示 示
在 找接后出上即缀其前87中后3缀59比2将861缀4344中此97大、变65找后52的1得5出为缀的标到比对翻7下号84换转一3大2最916个的大5。1数的24数77 5
1.5.2字典序法
对给定的字符集中的字符 规定了一个先后关系,在此基 础上规定两个全排列的先后是 从左到右逐个比较对应的字符 的先后。
1.5.2字典序法
[例]字符集{1,2,3},较小的数字较 先,这样按字典序生成的全排列是: 123,132,213,231,312,321。
※※ 一个全排列可看做一个字符串,字
规则:令n个元素为1,2,…,n. p p1 p2 pn 是 这n个数的任意一个排列,我们可以找到一 个序列和它对应,其中ai 可以看作是排列P中 数i+1所在位置右边比i+1小的数的个数。
例 排列3214,它是元素1,2,3,4的一个 排列, 它对应的序列是什么?
例 序列311对应的排列是什么?
练习
求839763ห้องสมุดไป่ตู้421的下一个排列
1.5.3邻位对换法
序数法和字典排序法,求下一个排列在 不进位的情况下很容易。这就启发我们, 能不能设计一种算法,下一个排列总是 上一个排列某相邻两位对换得到的。
活动状态
以1←2←3←4←为初始排列,箭头所指一侧,相邻 的数比它小时,则称该数组处在活动状态, 1 2 3←4←的←2←,3,4都处于的活动状态。
符串可有前缀、后缀。
排列组合的计算公式和算法

排列组合的计算公式和算法
排列组合的计算公式是:
全排列:A(n,n)=n!
组合:C(n,m)=A(n,m)/A(m,m)=n!/(m!*(n-m)!)
这个计算公式是通过对排列组合的一些基本概念的分析所得,所以其算法就是将排列组合的基本概念结合起来,从而得出最终计算结果。
具体的步骤如下:
1、首先,我们要弄清楚全排列和组合的概念,才能清楚的理解排列组合的计算公式。
2、然后,用这些基本概念去讨论排列组合的情况,得出一个公式去验证排列组合的情况是否正确。
3、接着,我们需要做出正确的推断,将基本概念和判断的概率公式综合起来,形成一个新的公式。
4、最后,用新的公式推导出排列组合的计算公式,并计算出结果。
全排列的几种实现(含字典序排列算法分析)

全排列的⼏种实现(含字典序排列算法分析) 始于⼀个很简单的问题:⽣成{0,1,2,3,...,n-1}的n!种排列,即全排列问题。
下⾯介绍⼏种全排列的实现,以及探讨⼀下其解题思路。
基于枚举/递归的⽅法思路: 基于枚举的⽅法,也可以说是基于递归的⽅法,此⽅法的思路是先将全排列问题的约束进⾏放松,形成⼀个较容易解决的新问题,解新问题,再对新问题进⾏约束,解出当前问题。
以上全排列问题是⽣成{0,1,2,...,n-1}的n!个排列,隐含的⼀个约束是这个n个位置上的数必须是给出的集合中的数,不能重复使⽤。
当我们将此约束放松的时候,问题就变成了n个位置每个位置上有0~n-1种可能出现的数字,列出所有n n种数列,即在每⼀位上枚举所有的可能。
新问题的算法⾮常简单:private Integer[] perm;private void permut(int pos, int n) {if (pos == n) {for (int i = 0; i < perm.length; i++) {System.out.print(perm[i]);}System.out.println();return;}for (int i = 0; i < n; i++) {perm[pos] = i;permut(pos+1, n);}} ⽽我们实际的问题只要保证每⼀位上的数字在其他位置上没有使⽤过就⾏了。
private boolean[] used;private Integer[] perm;private void permut(int pos, int n) {if (pos == n) {for (int i = 0; i < perm.length; i++) {System.out.print(perm[i]);}System.out.println();return;} //针对perm的第pos个位置,究竟使⽤0~n-1中的哪⼀个进⾏循环for (int i = 0; i < n; i++) {if (used[i] == false) {perm[pos] = i;used[i] = true; //i已经被使⽤了,所以把标志位设置为Truepermut(pos+1, n);used[i] = false; //使⽤完之后要把标志复位}}} 或者完全按递归是思想,对{0,1,2,...,n-1}进⾏排列,分别将每个位置交换到最前⾯位,之后全排列剩下的位:private static void PermutationList(int fromIndex, int endIndex){if (fromIndex == endIndex)Output();else{for (int index = fromIndex; index <= endIndex; ++index){// 此处排序主要是为了⽣成字典序全排列,否则递归会打乱字典序Sort(fromIndex, endIndex);Swap(fromIndex, index);PermutationList(fromIndex + 1, endIndex);Swap(fromIndex, index);}}}基于字典序的⽅法 基于字典序的⽅法,⽣成给定全排列的下⼀个排列,所谓⼀个的下⼀个就是这⼀个与下⼀个之间没有其他的。
算法设计与分析之全排列

将(1)中的a1,a2互换位置,得到(2); 将(1)中的a1,a3互换位置,得到(3).
可以用循环重复执行“交换位置,后跟剩余序列的所有排列”;对剩余的序列再使用该方法,直至没有剩余序列——递归调用
由排列组合的知识可知,n个元素的全排列共有n!种。 n!可分解为n*(n-1)!种,而 (n-1)!又分解为(n-1)(n-2)!种, 依次类推。
对于n个元素a=(a1a2……ak……an), 设过程range(a, k, n)是求a的第k到第n个元素的全排列。 算法如下: procedure range(a,k,n); 当k指向最后元素时, 递归终止,输出相应的字符串a 否则 i从k到n重复执行: 交换ak与ai ; range(a, k+1, n); 交换ak与ai ; endrange;
全排列
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的全排列的组合. 从而可以推断,设一组数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。 为了更容易理解,将整组数中的所有的数分别与第一个数交换,这样就总是在处理后n-1个数的全排列
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
全排列的生成算法对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。
字典序法按照字典序求下一个排列的算法 /*例字符集{1,2,3},较小的数字较先,这样按字典序生成的全排列是:123,132,213,231,312,321。
注意一个全排列可看做一个字符串,字符串可有前缀、后缀。
*/生成给定全排列的下一个排列所谓一个全排列的下一个排列就是这一个排列与下一个排列之间没有其他的排列。
这就要求这一个排列与下一个排列有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。
/*例是1—9的排列。
1—9的排列最前面的是,最后面的是,从右向左扫描若都是增的,就到了,也就没有下一个了。
否则找出第一次出现下降的位置。
算法: 由P1P2…Pn 生成的下一个排列的算法如下:1. 求i=max{j| Pj-1<Pj}2. 求l=max{k| Pi-1<Pk }3. 交换Pi-1 与Pl得到P1P2…Pi-1 (P i....Pn ) , 将红色部分顺序逆转,得到结果. 例求的下一个排列1. 确定i,从左到右两两比较找出后一个数比前一个大的组合,在这里有39 47,然后i取这些组中最到的位置号(不是最大的数)在这两组数中7的位置号最大为6,所以i=62.确定l,找出在i(包括i)后面的所有比i前面那一位大的数的最大的位置号,在此例中7,5 都满足要求,则选5,5的位置号为7,所以 l=73. 先将4和5交换,然后将5后的四位数倒转得到结果à以上算法是在数论课上老师给出的关于字典序全排列的生成算法,以前也经常要用到全排列生成算法来生成一个全排列对所有的情况进行测试,每次都是现到网上找一个算法,然后直接copy代码,修改一下和自己的程序兼容就行了,也不看是怎么来的,不是我不想看,实在是说的很抽象,那一大堆公式来吓人,一个实例都不给,更有甚者连算法都没有,只是在那里说,想看都看不懂,也没那个耐心取理解那些人写出来的那种让人无法忍受的解释。
不过在说别人的同时我也知道,自己写的也不够好,不过这就是我的理解了,没法子写的再细了。
全排列的生成算法2008年04月25日星期五下午03:23全排列的生成算法就是对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。
任何n个字符集的排列都可以与1~n的n个数字的排列一一对应,因此在此就以n个数字的排列为例说明排列的生成法。
n个字符的全体排列之间存在一个确定的线性顺序关系。
所有的排列中除最后一个排列外,都有一个后继;除第一个排列外,都有一个前驱。
每个排列的后继都可以从它的前驱经过最少的变化而得到,全排列的生成算法就是从第一个排列开始逐个生成所有的排列的方法。
全排列的生成法通常有以下几种:字典序法递增进位数制法递减进位数制法邻位交换法n进位制法递归类算法1.字典序法字典序法中,对于数字1、2、3......n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。
例如对于5个数字的排列12354和12345,排列12345在前,排列12354在后。
按照这样的规定,5个数字的所有的排列中最前面的是12345,最后面的是54321。
字典序算法如下:设P是1~n的一个全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn1)从排列的右端开始,找出第一个比右边数字小的数字的序号j(j从左端开始计算),即j=max{i|pi<pi+1} 2)在pj的右边的数字中,找出所有比pj大的数中最小的数字pk,即k=max{i|pi>pj}(右边的数从右至左是递增的,因此k是所有大于pj的数字中序号最大者)3)对换pi,pk4)再将pj+1......pk-1pkpk+1pn倒转得到排列p'=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,这就是排列p的下一个下一个排列。
例如是数字1~9的一个排列。
从它生成下一个排列的步骤如下:自右至左找出排列中第一个比右边数字小的数字4在该数字后的数字中找出比4大的数中最小的一个5将5与4交换将7421倒转所以的下一个排列是。
程序代码如下:Private Sub Dict(p() As Integer, ByVal n As Integer)Dim i As Integer, j As IntegerOutL pi = n - 1Do While i > 0If p(i) < p(i + 1) ThenFor j = n To i + 1 Step -1 '从排列右端开始If p(i) <= p(j) Then Exit For '找出递减子序列NextSwap p(i), p(j) '将递减子序列前的数字与序列中比它大的第一个数交换For j = n To 1 Step -1 '将这部分排列倒转i = i + 1If i >= j Then Exit For2Swap p(i), p(j)NextOutL p '输出一个排列i = nEnd Ifi = i - 1LoopEnd SubSwap p(i), p(j)是交换两个元素的子过程,OutL p是输出排列的子过程。
2.递增进位数制法在递增进位制数法中,从一个排列求另一个排列需要用到中介数。
如果用ki表示排列p1p2...pi...pn中元素pi的右边比pi小的数的个数,则排列的中介数就是对应的排列k1 ...... ki...... kn-1。
例如排列的中介数是,7、2、6、......分别是排列中数字8、3、9、......的右边比它小的数字个数。
中介数是计算排列的中间环节。
已知一个排列,要求下一个排列,首先确定其中介数,一个排列的后继,其中介数是原排列中介数加1,需要注意的是,如果中介数的末位kn-1+1=2,则要向前进位,一般情形,如果ki+1=n-i+1,则要进位,这就是所谓的递增进位制。
例如排列的中介数是,则下一个排列的中介数是+1=(因为1+1=2,所以向前进位,2+1=3,又发生进位,所以下一个中介数是)。
得到中介数后,可根据它还原对应得排列。
算法如下:中介数k1、k2、......、kn-1的各位数字顺序表示排列中的数字n、n-1、......、2在排列中距右端的的空位数,因此,要按k1、k2、......、kn-1的值从右向左确定n、n-1、......、2的位置,并逐个放置在排列中:i放在右起的ki+1位,如果某位已放有数字,则该位置不算在内,最后一个空位放1。
因此从可得到排列,它就是的后一个排列。
因为9最先放置,k1=6,9放在右起第7位,空出6个空位,然后是放8,k2=7,8放在右起第8位,但9占用一位,故8应放在右起第9位,余类推。
程序代码如下:Private Sub Incr(p() As Integer, ByVal n As Integer)Dim m() As Integer '保存中介数的数组Dim i As Integer, j As IntegerDim a As IntegerReDim m(n)For i = 1 To n '第一个排列的中介数为000 0m(i) = 0NextDo While n > 0For i = 1 To n '排列的各位为0p(i) = 0NextFor i = 1 To n '从右向左察看排列中为0的位a = m(i) + 1j = nDo While j > 0If p(j) = 0 Thena = a - 1If a = 0 Then Exit Do '0的个数决定数字i的位置End Ifj = j - 1Loopp(j) = n - i + 1 '将数字i放置在指定位置NextOutL pIf MedN(m) Then Exit Do '计算下一个中介数,如果是00...0,则全部排列找到LoopEnd SubPrivate Function MedN(m() As Integer)As Boolean '计算中介数函数Dim i As Integer, sum As IntegerDim b As Booleanb = Falsei = n - 1Do While i > 0m(i) = m(i) + 1If m(i) < n - i + 1 Then Exit Dom(i) = 0i = i - 1LoopSum = 0For i = 1 To n - 1 '计算中介数各位之和Sum = Sum + m(i)NextIf Sum = 0 Then b = True '中介数各位之和为0MedN = b4End Function3.递减进位制数法在递增进位制数法中,中介数的最低位是逢2进1,进位频繁,这是一个缺点。
把递增进位制数翻转,就得到递减进位制数。
的中介数是(k1k2…kn-1),倒转成为(kn-1…k2k1),这是递减进位制数的中介数:ki(i=n-1,n-2,…,2)位逢i向ki-1位进1。
给定排列p,p的下一个排列的中介数定义为p的中介数加1。
例如p=,p 的中介数为,p的下一个排列的中介数为+1=,由此得到p的下一个排列为。
给定中介数,可用与递增进位制数法类似的方法还原出排列。
但在递减进位制数中,可以不先计算中介数就直接从一个排列求出下一个排列。
具体算法如下:1)如果p(i)=n且i<>n,则p(i)与p(i-1)交换2)如果p(n)=n,则找出一个连续递减序列9、8、......、i,将其从排列左端删除,再以相反顺序加在排列右端,然后将i-1与左边的数字交换例如p=的下一个排列是。
求的下一个排列时,因为9在最左边且第2位为8,第3位不是7,所以将8和9从小到大排于最右端,再将7与其左方数字对调得到的下一个排列是。
又例如求的下一个排列,只需要将9876从小到大排到最右端并将5与其左方数字3对调,得到。
程序代码如下:Private Sub Degr(p() As Integer, ByVal n As Integer)Dim i As Integer, j As IntegerDo While n > 0OutL pIf p(1) = n Then '如果第一位是ni = 0Do '从左端开始找出最长的连续递降序列i = i + 1If i = n Then Exit SubLoop Until p(i) <> p(i + 1) + 1j = iDo '找出递降序列末尾数字的下一个数字i = i + 1Loop Until p(i) = p(j) - 1Swap p(i), p(i - 1) '将它与序列末尾数字交换For i = 1 To n - j '将递减序列倒转后放置在排列右端p(i) = p(i + j)NextFor i = 1 To jp(n - i + 1) = n - i + 1NextElse '如果最高位不是ni = 0 '从左端开始Do '找出n所在位置i = i + 1Loop Until p(i) = nSwap p(i), p(i - 1) '将n与其左边数字交换End IfLoopEnd Sub4.邻位对换法邻位对换法中下一个排列总是上一个排列某相邻两位对换得到的。