《全排列生成算法》由会员分享,可在线阅读,更多相关《全排列生成算法(13页珍藏版)》请在金锄头文库上搜索。
1、全排列的生成算法对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚 举出来。字典序法按照字典序求下一个排列的算法/*例字符集1,2,3,较小的数字较先,这样按 字典序生成的全排列是:123,132,213,231,312,321。注意一个全排列可看做一个字符串,字符 串可有前缀、后缀。*/生成给定全排列的下一个排列所谓一个全排列的下一个排列就是这一个 排列与下一个排列之间没有其他的排列。这就要求这一个排列与下一个排列有尽可能长的共 同前缀,也即变化限制在尽可能短的后缀上。/*例是19的排列。19的排列最前面的是, 最后面的是,从右向左扫描若都是增的,就到了,也就没有下一个了。否则
2、找出第一次出现 下降的位置。算法:由P1P2.n生成的下一个排列的算法如下:1.求i=maxj| Pj-1Pj2.求 l=maxk| Pi-1Pk 3.交换 Pi-1 与 Pl 得到 P1P2.Pi-1 (P i.Pn ),将红色部分顺序逆转, 得到结果.例求的下一个排列1.确定i,从左到右两两比较找出后一个数比前一个大的组合, 在这里有39 47,然后i取这些组中最到的位置号(不是最大的数)在这两组数中7的位置号 最大为6,所以62.确定l,找出在i (包括i)后面的所有比i前面那一位大的数的最大的位 置号,在此例中7, 5都满足要求,则选5, 5的位置号为7,所以l=73.先将4和5交换,
3、 然后将5后的四位数倒转得到结果a以上算法是在数论课上老师给出的关于字典序全排列的 生成算法,以前也经常要用到全排列生成算法来生成一个全排列对所有的情况进行测试,每 次都是现到网上找一个算法,然后直接copy代码,修改一下和自己的程序兼容就行了,也不 看是怎么来的,不是我不想看,实在是说的很抽象,那一大堆公式来吓人,一个实例都不给, 更有甚者连算法都没有,只是在那里说,想看都看不懂,也没那个耐心取理解那些人写出来 的那种让人无法忍受的解释。不过在说别人的同时我也知道,自己写的也不够好,不过这就 是我的理解了,没法子写的再细了。全排列的生成算法2008年04月25日 星期五 下午03:23全排列
4、的生成算法就是对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。任 何n个字符集的排列都可以与1n的n个数字的排列一一对应,因此在此就以n个数字的排列为例说明排 列的生成法。n个字符的全体排列之间存在一个确定的线性顺序关系。所有的排列中除最后一个排列外,都有一个后继; 除第一个排列外,都有一个前驱。每个排列的后继都可以从 它 的前驱经过最少的变化而得到,全排列的生 成算法就是从第一个排列开始逐个生成所有的排列的方法。全排列的生成法通常有以下几种:字典序法递增进位数制法递减进位数制法邻位交换法n进位制法递归类算法1. 字典序法字典序法中,对于数字1、2、3.n的排列,不同排
5、列的先后关系是从左到右逐个比较对应的数字的先后来 决定的。例如对于5个数字的排列12354和12345,排列12345在前,排列12354在后。按照这样的规定, 5个数字的所有的排列中最前面的是12345,最后面的是54321。字典序算法如下:设 P 是 1 n 的一个全排列:p=p1p2pn=p1p2pj-1pjpj+1pk-1pkpk+1pn1) 从排列的右端开始,找出第一个比右边数字小的数字的序号j(j从左端开始计算),即j=maxi|pipj(右边的数从右至左是 递增的,因此k是所有大于pj的数字中序号最大者)3) 对换 pi,pk4) 再将 pj+1 pk-1pkpk+1pn 倒转得
6、到排列 p=p1p2.pj-1pjpn.pk+1pkpk-1.pj+1,这就是排列 p 的下 一个下一个排列。例如是数字19的一个排列。从它生成下一个排列的步骤如下:自右至左找出排列中第一个比右边数字小的数字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
7、 i + 1 Step -1从排列右端开始If p(i) = j Then Exit ForSwap 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的右边比它小的数字个数。中介数是计
8、算排列的中间环节。巳知一个排列,要求下一个排列,首先确定其中介数,一个排列的后继,其 中介数是原排列中介数加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的位置,并逐个放置在排
9、列中: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第一个排列的中介
10、数为000.0m(i) = 0NextDo While n 0p(i) = 0NextFor i = 1 To n从右向左察看排列中为0的位a = m(i) + 1Do While j 0If p(j) = 0 ThenIf a = 0 Then Exit Do0的个数决定数字i的位置End IfLoopp(j) = n - i + 1将数字i放置在指定位置NextOutL pIf MedN(m) Then Exit Do计算下一个中介数,如果是00.0,则全部排列找到LoopEnd SubPrivate Function MedN(m() As Integer)As Boolean计算中介数
11、函数Dim i As Integer, sum As IntegerDim b As Booleanb = FalseDo While i 0m(i) = m(i) + 1If m(i) n - i + 1 Then Exit Dom(i) = 0LoopSum = 0For i = 1 To n - 1计算中介数各位之和Sum = Sum + m(i)NextIf Sum = 0 Then b = True中介数各位之和为0MedN = bEnd Function3. 递减进位制数法在递增进位制数法中,中介数的最低位是逢2进1,进位频繁,这是一个缺点。把递增进位制数翻转,就得到 递减进位制数
12、。的中介数是(k1k2.kn-1)ki-1位进1。给定排列p,倒转成为(kn-1.k2k1),这是递减进位制数的中介数:ki(i=n-1,n-2,.,2)位逢i向p的下一个排列的中介数定义为p的中介数加1。例如p=,p的中介数为,p的下一个排列的中介数为+1=由此得到p的下一个排列为。给定中介数,可用与递增进位制数法类似的方法还原出排列。但在递减进位制数中,可以不先计算中介数就 直接从一个排列求出下一个排列。具体算法如下:1)如果 p(i)=n 且 in,则 p(i)与 p(i-1)交换2)如果p(n)=n,则找出一个连续递减序列9、8、i,将其从排列左端删除,再以相反顺序加在排列右端,然后将
13、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如果第一位是nDo从左端开始找出最长的连续递降序列If i = n Then Exit
14、 SubLoop Until p(i) p(i + 1) + 1Do找出递降序列末尾数字的下一个数字Loop Until p(i) = p(j) - 1Swap p(i), p(i - 1)将它与序列末尾数字交换For i = 1 To n - j将递减序列倒转后放置在排列右端p(i) = p(i + j)Nextp(n - i + 1) = n - i + 1NextElse如果最高位不是n从左端开始Do找出n所在位置Loop Until p(i) = nSwap p(i), p(i - 1)将n与其左边数字交换End IfLoopEnd Sub4. 邻位对换法邻位对换法中下一个排列总是上一个排列某相邻两位对换得到的。以4个元素的排列为例,将最后的元素4逐次与前面的元素交换,可以生成4个新排列:1 2 3 4 1 2 4 3 1 4 2 3 4 1 2 3然后将最后一个排列的末尾的两个元素交换,再逐次将排头的4与其后的元素交换,又生成四个新排列:4 1 3 2 1 4 3 2 1 3 4 2 1