哈里在最近的編程生活中,突發奇想,開始着手文本的分析。
期間涉及到了數組的排序。於是想也沒想祭出了自己祖傳的“撲克牌排序法”,即插值排序。
不過當後期數組元素個數大於100萬的時候,祖傳方法明顯慢了下來,需要長達幾十分鐘的排序(VB.6.0與VB.net均如此,VB6.0更慢)。
在排序算法的優化中,想到了一種新型排序方法:預留排序法。(新算法100萬條數據僅需29毫秒,名字起的比較隨意)
預留排序法的步驟主要有三步:
1、找到需要排序數組的最小值與最大值。(如果語言不支持負數組,則利用一個偏移將負值偏移至0)
2、獲取需要排序數組的每種出現過的值的重複數量。
3、通過內存位置預測,將需要排序的數組的遍歷序放入排序索引數組完成排序。
(以下例子默認需要排序的最小值大於或等於1)
VB6.0實例如下:(百萬條數據3.6秒)
Public Function 預留法排序(數組() As Long, 排序() As Long)
Dim 數量() As Long, i As Long, 數組最大值 As Long, 偏移() As Long
ReDim 排序(UBound(數組))
For i = 1 To UBound(數組)
If 數組(i) > 數組最大值 Then
數組最大值 = 數組(i)
End If
Next
ReDim 數量(數組最大值), 偏移(數組最大值)
For i = 1 To UBound(數組)
數量(數組(i)) = 數量(數組(i)) + 1
Next
For i = 1 To UBound(數組)
偏移(數組(i)) = 偏移(數組(i)) + 1
排序(數組求和(數量, 數組(i)) + 偏移(數組(i))) = i
Next
End Function
Private Function 數組求和(數組() As Long, 截止序 As Long) As Long
Dim i As Long
For i = LBound(數組) To 截止序 - 1
數組求和 = 數組求和 + 數組(i)
Next
End Function
不得不說VB.NET的運算速度比VB6.0快得多得多,所以VB.net的實例哈里也準備了一份:(百萬條數據29毫秒)
Public Sub 預留法排序(數組() As Long, 排序() As Long)
Dim 數量() As Long, i As Long, 數組最大值 As Long, 偏移() As Long
ReDim 排序(UBound(數組))
'獲得數組最大值
For i = 1 To UBound(數組)
If 數組(i) > 數組最大值 Then
數組最大值 = 數組(i)
End If
Next
ReDim 數量(數組最大值), 偏移(數組最大值)
'重複值劃分統計
For i = 1 To UBound(數組)
數量(數組(i)) += 1
Next
'最終排序
For i = 1 To UBound(數組)
偏移(數組(i)) += 1
排序(數組求和(數量, 數組(i)) + 偏移(數組(i))) = i
Next
End Function
Private Function 數組求和(數組() As Long, 截止序 As Long) As Long
Dim i As Long, 輸出 As Long
For i = LBound(數組) To 截止序 - 1
輸出 += 數組(i)
Next
Return 輸出
End Function
(PS:以上所有耗時數據基於Intel i9 9900K默頻。)