2012-07-16 114 views
9

按照降序排序一組數字(1000-10000個數字,但可能會有所不同)的最快方法是什麼(按計算時間)?據我所知,Excel內置函數不是很有效,而且內存中的排序應該比Excel函數快得多。Excel VBA按照降序對數組進行排序的最快方法?

請注意,我無法在電子表格上創建任何內容,所有內容都必須存儲並僅存儲在內存中。

+9

排序數組的完整教程。埃利斯給了你很多選擇排序數組:)你可以選擇。 http://www.vbforums.com/showthread.php?t=473677 – 2012-07-16 12:40:51

+1

查看帖子http://stackoverflow.com/a/11012529/797393。 – Cylian 2012-07-16 12:43:39

回答

1

爲了讓人們不必點擊我剛剛做的鏈接,這裏就是來自Siddharth評論的一個很棒的例子。

Option Explicit 
Option Compare Text 

' Omit plngLeft & plngRight; they are used internally during recursion 
Public Sub QuickSort(ByRef pvarArray As Variant, Optional ByVal plngLeft As Long, Optional ByVal plngRight As Long) 
    Dim lngFirst As Long 
    Dim lngLast As Long 
    Dim varMid As Variant 
    Dim varSwap As Variant 

    If plngRight = 0 Then 
     plngLeft = LBound(pvarArray) 
     plngRight = UBound(pvarArray) 
    End If 
    lngFirst = plngLeft 
    lngLast = plngRight 
    varMid = pvarArray((plngLeft + plngRight) \ 2) 
    Do 
     Do While pvarArray(lngFirst) < varMid And lngFirst < plngRight 
      lngFirst = lngFirst + 1 
     Loop 
     Do While varMid < pvarArray(lngLast) And lngLast > plngLeft 
      lngLast = lngLast - 1 
     Loop 
     If lngFirst <= lngLast Then 
      varSwap = pvarArray(lngFirst) 
      pvarArray(lngFirst) = pvarArray(lngLast) 
      pvarArray(lngLast) = varSwap 
      lngFirst = lngFirst + 1 
      lngLast = lngLast - 1 
     End If 
    Loop Until lngFirst > lngLast 
    If plngLeft < lngLast Then QuickSort pvarArray, plngLeft, lngLast 
    If lngFirst < plngRight Then QuickSort pvarArray, lngFirst, plngRight 
End Sub 
0

我不知道使用工作表,但其值得注意的是,創建一個新的工作表,使用它作爲一個便箋做排序與工作表函數指定的OP,然後不到一個因素後清理愈長爲2.但您也具有Sort WorkSheet Function的參數提供的所有靈活性。

在我的系統中,@ tannman357的非常漂亮的遞歸例程與下面的方法的差別爲55毫秒,96毫秒。這些是幾次運行的平均時間。

Sub rangeSort(ByRef a As Variant) 
Const myName As String = "Module1.rangeSort" 
Dim db As New cDebugReporter 
    db.Report caller:=myName 

Dim r As Range, va As Variant, ws As Worksheet 

    quietMode qmON 
    Set ws = ActiveWorkbook.Sheets.Add 
    Set r = ws.Cells(1, 1).Resize(UBound(a), 1) 
    r.Value2 = rangeVariant(a) 
    r.Sort Key1:=r.Cells(1), Order1:=xlDescending 
    va = r.Value2 
    GetColumn va, a, 1 
    ws.Delete 
    quietMode qmOFF 

End Sub 

Function rangeVariant(a As Variant) As Variant 
Dim va As Variant, i As Long 

    ReDim va(LBound(a) To UBound(a), 0) 

    For i = LBound(a) To UBound(a) 
    va(i, 0) = a(i) 
    Next i 
    rangeVariant = va 

End Function 

Sub quietMode(state As qmState) 
Static currentState As Boolean 

    With Application 

    Select Case state 
    Case qmON 
     currentState = .ScreenUpdating 
     If currentState Then .ScreenUpdating = False 
     .Calculation = xlCalculationManual 
     .DisplayAlerts = False 
    Case qmOFF 
     If currentState Then .ScreenUpdating = True 
     .Calculation = xlCalculationAutomatic 
     .DisplayAlerts = True 
    Case Else 
    End Select 

    End With 
End Sub 
0

如果你想要高效的算法,那麼看看Timsort。它是適應合併排序,修復它的問題。

Case Timsort  Introsort Merge sort Quicksort Insertion sort Selection sort 
Best Ɵ(n)  Ɵ(n log n) Ɵ(n log n) Ɵ(n)  Ɵ(n^2)   Ɵ(n) 
Average Ɵ(n log n) Ɵ(n log n) Ɵ(n log n) Ɵ(n log n) Ɵ(n^2)   Ɵ(n^2) 
Worst Ɵ(n log n) Ɵ(n log n) Ɵ(n log n) Ɵ(n^2)  Ɵ(n^2)   Ɵ(n^2) 

但是,1k-10k數據條目數量太少,您不必擔心內置的搜索效率。


示例:如果有從柱的數據到d頭是在第2行並且要通過塔B進行排序。

Dim lastrow As Long 
lastrow = Cells(Rows.Count, 2).End(xlUp).Row 
Range("A3:D" & lastrow).Sort key1:=Range("B3:B" & lastrow), _ 
    order1:=xlAscending, Header:=xlNo 
5

你可以使用System.Collections.ArrayList

Dim arr As Object 
Dim cell As Range 

Set arr = CreateObject("System.Collections.ArrayList") 

' Initialise the ArrayList, for instance by taking values from a range: 
For Each cell In Range("A1:F1") 
    arr.Add cell.Value 
Next 

arr.Sort 
' Optionally reverse the order 
arr.Reverse 

這使用快速排序。

+0

偶然發現並試圖在一個子實現這個。它似乎在'arr.sort'之後退出,無法通過這條線。 – Tom 2017-03-13 10:36:18

+0

我剛纔重複了這個,它工作正常。你在排序什麼數據?它有多大?你有沒有嘗試過幾個值? (我現在就做了,對我來說工作正常)。 – trincot 2017-03-13 10:42:30

+0

我試着用一個數組填充46個Double值。我需要添加參考嗎? (我知道這是使用後期綁定,但不知道爲什麼它會退出,沒有調試錯誤) – Tom 2017-03-13 10:44:39

1

我已經成功地使用了Shell排序算法。在使用由VBA Rnd()函數生成的數組進行N = 10000測試時運行一眨眼之間 - 不要忘記使用Randomize語句來生成測試數組。對於我正在處理的元素的數量來說,實施起來很簡單,效率也很高。代碼註釋中給出了參考。

' Shell sort algorithm for sorting a double from largest to smallest. 
' Adopted from "Numerical Recipes in C" aka NRC 2nd Edition p330ff. 
' Speed is on the range of N^1.25 to N^1.5 (somewhere between bubble and quicksort) 
' Refer to the NRC reference for more details on efficiency. 
' 
Private Sub ShellSortDescending(ByRef a() As Double, N As Integer) 

    ' requires a(1..N) 

    Debug.Assert LBound(a) = 1 

    ' setup 

    Dim i, j, inc As Integer 
    Dim v As Double 
    inc = 1 

    ' determine the starting incriment 

    Do 
     inc = inc * 3 
     inc = inc + 1 
    Loop While inc <= N 

    ' loop over the partial sorts 

    Do 
     inc = inc/3 

     ' Outer loop of straigh insertion 

     For i = inc + 1 To N 
      v = a(i) 
      j = i 

      ' Inner loop of straight insertion 
      ' switch to a(j - inc) > v for ascending 

      Do While a(j - inc) < v 
       a(j) = a(j - inc) 
       j = j - inc 
       If j <= inc Then Exit Do 
      Loop 
      a(j) = v 
     Next i 
    Loop While inc > 1 
End Sub 
相關問題