非递归实现不重复序列的全排列(三)

?笔者曾利用进制转换实现不重复序列全排列(http://blog.csdn.net/northwolves/archive/2004/07/21/47400.aspx),但从0 循环到n^(n-1)-1,效率实在不高,经过仔细分析,发现一个另人激动的规律,详情见下表:

?

A<o:p></o:p>

<o:p>?</o:p>

BA<o:p></o:p>

CBA<o:p></o:p>

DCBA<o:p></o:p>

CDBA<o:p></o:p>

CBDA<o:p></o:p>

CBAD<o:p></o:p>

BCA<o:p></o:p>

DBCA<o:p></o:p>

BDCA<o:p></o:p>

BCDA<o:p></o:p>

BCAD<o:p></o:p>

BAC<o:p></o:p>

DBAC<o:p></o:p>

BDAC<o:p></o:p>

BADC<o:p></o:p>

BACD<o:p></o:p>

AB<o:p></o:p>

CAB<o:p></o:p>

DCAB<o:p></o:p>

CDAB<o:p></o:p>

CADB<o:p></o:p>

CABD<o:p></o:p>

ACB<o:p></o:p>

DACB<o:p></o:p>

ADCB<o:p></o:p>

ACDB<o:p></o:p>

ACBD<o:p></o:p>

ABC<o:p></o:p>

DABC<o:p></o:p>

ADBC<o:p></o:p>

ABDC<o:p></o:p>

ABCD<o:p></o:p>

从上面表格可以看出,对于“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 Single
Dim i As Integer, j As Integer, Num As Long, n As Integer
Dim ALL As New Collection, TEMP1 As Long, TEMP2 As Long
n = UBound(x) + 1 '元素个数
starttime = Timer '开始计时
Num = 1
For i = 1 To n
Num = Num * i? '递归计算n!
Next
For i = 1 To Num
Set ALL = Nothing '初始化集合all
ALL.Add x(0)
TEMP1 = i
For j = 2 To n
TEMP2 = TEMP1 Mod j
TEMP1 = TEMP1 \ j
If TEMP2 = 0 Then
ALL.Add x(j - 1) 'temp2为 0则放在最后
Else
ALL.Add x(j - 1), , BEFORE:=TEMP2 'temp2不为 0 则置于第temp2个元素前
End If
Next
For j = 1 To n
Debug.Print ALL(j) & " "; '输出
Next
Debug.Print
Next
endtime = Timer
Debug.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 Single
Dim i As Integer, j As Integer, k As Integer, Num As Long, n As Integer
Dim ALL(), TEMP1 As Long, TEMP2 As Long
n = UBound(x) + 1 '元素个数

starttime = Timer '开始计时
Num = 1
For i = 1 To n
Num = Num * i? '递归计算n!
Next
For i = 1 To Num
ReDim ALL(1 To n) '初始化数组all
ALL(1) = x(0)
TEMP1 = i
For j = 2 To n
TEMP2 = TEMP1 Mod j
TEMP1 = TEMP1 \ j
If TEMP2 = 0 Then
ALL(j) = x(j - 1) 'temp2为 0则放在最后
Else
For k = j To TEMP2 + 1 Step -1
ALL(k) = ALL(k - 1)? ' temp2之后的元素后移一位
Next
ALL(TEMP2) = x(j - 1) 'temp2不为 0 则置于第temp2个元素前
End If
Next
Debug.Print Join(ALL, " ")? '输出
Next
endtime = Timer
Debug.Print "共 " & Num & " 种排列!用时 " & endtime - starttime & " 秒!"
End Sub
Private Sub Command1_Click()
pailie4 "a", "b", "c", "d", "e", "f", "g"
End Sub

如果用COPYMEMORY进行数组的移动,速度应该更快,大家有兴趣不妨一试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值