笔者曾利用进制转换实现不重复序列全排列(http://blog.csdn.net/northwolves/archive/2004/07/21/47400.aspx),但从0 循环到n^(n-1)-1,效率实在不高,经过仔细分析,发现一个另人激动的规律,详情见下表:
A | BA | CBA | DCBA |
CDBA |
CBDA |
CBAD |
BCA | DBCA |
BDCA |
BCDA |
BCAD |
BAC | DBAC |
BDAC |
BADC |
BACD |
AB | CAB | DCAB |
CDAB |
CADB |
CABD |
ACB | DACB |
ADCB |
ACDB |
ACBD |
ABC | DABC |
ADBC |
ABDC |
ABCD |
从上面表格可以看出,对于“ABCD”,假如先放好A(只有一种放法),再放B时,可以有BA,AB两种放法;再放C时,则针对BA,AB 各有3种放法(BA前,BA中,BA后),再放D时,各有4种放法。所以第一个元素排好后,第2个元素的位置可以用0,1 表示,第3个元素的位置可以用0,1 ,2表示,第n个元素的位置可以用0,1 ,2,3,...n-1表示,因而使用混合进制(笔者起的名字)可以实现数组元素的全排列。
代码如下:
Sub pailie3(ParamArray x())Dim starttime As Single, endtime As SingleDim i As Integer, j As Integer, Num As Long, n As IntegerDim ALL As New Collection, TEMP1 As Long, TEMP2 As Longn = UBound(x) + 1 '元素个数starttime = Timer '开始计时Num = 1For i = 1 To nNum = Num * i '递归计算n!NextFor i = 1 To NumSet ALL = Nothing '初始化集合allALL.Add x(0)TEMP1 = iFor j = 2 To nTEMP2 = TEMP1 Mod jTEMP1 = TEMP1 \ jIf TEMP2 = 0 ThenALL.Add x(j - 1) 'temp2为 0则放在最后ElseALL.Add x(j - 1), , BEFORE:=TEMP2 'temp2不为 0 则置于第temp2个元素前End IfNextFor j = 1 To nDebug.Print ALL(j) & " "; '输出NextDebug.PrintNextendtime = TimerDebug.Print "共 " & Num & " 种排列!用时 " & endtime - starttime & " 秒!"End Sub
Private Sub Command1_Click()pailie3 "a", "b", "c", "d", "e", "f", "g"End Sub
由于集合属于VARIANT类型,运算速度慢,换成数组进行同样的转换,发现确实快了很多:
Sub pailie4(ParamArray x())Dim starttime As Single, endtime As SingleDim i As Integer, j As Integer, k As Integer, Num As Long, n As IntegerDim ALL(), TEMP1 As Long, TEMP2 As Longn = UBound(x) + 1 '元素个数
starttime = Timer '开始计时Num = 1For i = 1 To nNum = Num * i '递归计算n!NextFor i = 1 To NumReDim ALL(1 To n) '初始化数组allALL(1) = x(0)TEMP1 = iFor j = 2 To nTEMP2 = TEMP1 Mod jTEMP1 = TEMP1 \ jIf TEMP2 = 0 ThenALL(j) = x(j - 1) 'temp2为 0则放在最后ElseFor k = j To TEMP2 + 1 Step -1ALL(k) = ALL(k - 1) ' temp2之后的元素后移一位NextALL(TEMP2) = x(j - 1) 'temp2不为 0 则置于第temp2个元素前End IfNextDebug.Print Join(ALL, " ") '输出Nextendtime = TimerDebug.Print "共 " & Num & " 种排列!用时 " & endtime - starttime & " 秒!"End SubPrivate Sub Command1_Click()pailie4 "a", "b", "c", "d", "e", "f", "g"End Sub
如果用COPYMEMORY进行数组的移动,速度应该更快,大家有兴趣不妨一试。