VBA数组排序功能?

Mar*_*old 79 arrays sorting vb6 vba ms-project

我正在为VBA中的数组寻找合适的排序实现.Quicksort将是首选.或任何其他排序算法除了冒泡或合并之外的就足够了.

请注意,这是为了与MS Project 2003一起使用,因此应避免使用任何Excel本机函数和任何.net相关的函数.

Jor*_*ira 93

看看这里:
编辑: 引用的源(allexperts.com)已关闭,但以下是相关的作者评论:

网上有许多可用于排序的算法.最通用,通常最快的是Quicksort算法.以下是它的功能.

只需通过下部数组边界(通常0)和上部数组边界(即UBound(myArray).)传递一个值数组(字符串或数字;无关紧要)来调用它

示例:Call QuickSort(myArray, 0, UBound(myArray))

完成后,myArray将进行排序,您可以随心所欲地进行操作.
(来源:archive.org)

Public Sub QuickSort(vArray As Variant, inLow As Long, inHi As Long)
  Dim pivot   As Variant
  Dim tmpSwap As Variant
  Dim tmpLow  As Long
  Dim tmpHi   As Long

  tmpLow = inLow
  tmpHi = inHi

  pivot = vArray((inLow + inHi) \ 2)

  While (tmpLow <= tmpHi)
     While (vArray(tmpLow) < pivot And tmpLow < inHi)
        tmpLow = tmpLow + 1
     Wend

     While (pivot < vArray(tmpHi) And tmpHi > inLow)
        tmpHi = tmpHi - 1
     Wend

     If (tmpLow <= tmpHi) Then
        tmpSwap = vArray(tmpLow)
        vArray(tmpLow) = vArray(tmpHi)
        vArray(tmpHi) = tmpSwap
        tmpLow = tmpLow + 1
        tmpHi = tmpHi - 1
     End If
  Wend

  If (inLow < tmpHi) Then QuickSort vArray, inLow, tmpHi
  If (tmpLow < inHi) Then QuickSort vArray, tmpLow, inHi
End Sub
Run Code Online (Sandbox Code Playgroud)

请注意,这仅适用于一维(又名"普通"?)数组.(有一个工作的多维arraye快速排序在这里.)

  • @ElieG。- 我知道这个评论已经过时了,但是对于有同样问题的其他人来说,vba 有两个用于除法的运算符。/ 将结果除并四舍五入为最接近的整数。\ 进行整数除法并截去结果的小数部分 (4认同)
  • 处理重复项时,这是稍微快一点的实现.可能是由于\ 2.很好的答案:) (2认同)
  • @Egalth-我已经用原始来源上的信息更新了问题 (2认同)
  • 为了正确使用它进行区分大小写的字符串比较,我在模块的开头使用“Option Compare Text”,否则它使用二进制比较。 (2认同)

Ala*_*ain 16

如果其他人想要的话,我将'快速快速排序'算法转换为VBA.

我已将其优化为在Int/Longs数组上运行,但将其转换为适用于任意可比元素的数组应该很简单.

Private Sub QuickSort(ByRef a() As Long, ByVal l As Long, ByVal r As Long)
    Dim M As Long, i As Long, j As Long, v As Long
    M = 4

    If ((r - l) > M) Then
        i = (r + l) / 2
        If (a(l) > a(i)) Then swap a, l, i '// Tri-Median Methode!'
        If (a(l) > a(r)) Then swap a, l, r
        If (a(i) > a(r)) Then swap a, i, r

        j = r - 1
        swap a, i, j
        i = l
        v = a(j)
        Do
            Do: i = i + 1: Loop While (a(i) < v)
            Do: j = j - 1: Loop While (a(j) > v)
            If (j < i) Then Exit Do
            swap a, i, j
        Loop
        swap a, i, r - 1
        QuickSort a, l, j
        QuickSort a, i + 1, r
    End If
End Sub

Private Sub swap(ByRef a() As Long, ByVal i As Long, ByVal j As Long)
    Dim T As Long
    T = a(i)
    a(i) = a(j)
    a(j) = T
End Sub

Private Sub InsertionSort(ByRef a(), ByVal lo0 As Long, ByVal hi0 As Long)
    Dim i As Long, j As Long, v As Long

    For i = lo0 + 1 To hi0
        v = a(i)
        j = i
        Do While j > lo0
            If Not a(j - 1) > v Then Exit Do
            a(j) = a(j - 1)
            j = j - 1
        Loop
        a(j) = v
    Next i
End Sub

Public Sub sort(ByRef a() As Long)
    QuickSort a, LBound(a), UBound(a)
    InsertionSort a, LBound(a), UBound(a)
End Sub
Run Code Online (Sandbox Code Playgroud)

  • 感谢上帝,我发布了这个.3个小时后,我崩溃了,失去了我一天的工作,但至少能够恢复这个.现在,这就是Karma在工作.电脑很难. (17认同)

Kon*_*lph 10

德语解释但代码是经过充分测试的就地实现:

Private Sub QuickSort(ByRef Field() As String, ByVal LB As Long, ByVal UB As Long)
    Dim P1 As Long, P2 As Long, Ref As String, TEMP As String

    P1 = LB
    P2 = UB
    Ref = Field((P1 + P2) / 2)

    Do
        Do While (Field(P1) < Ref)
            P1 = P1 + 1
        Loop

        Do While (Field(P2) > Ref)
            P2 = P2 - 1
        Loop

        If P1 <= P2 Then
            TEMP = Field(P1)
            Field(P1) = Field(P2)
            Field(P2) = TEMP

            P1 = P1 + 1
            P2 = P2 - 1
        End If
    Loop Until (P1 > P2)

    If LB < P2 Then Call QuickSort(Field, LB, P2)
    If P1 < UB Then Call QuickSort(Field, P1, UB)
End Sub
Run Code Online (Sandbox Code Playgroud)

像这样调用:

Call QuickSort(MyArray, LBound(MyArray), UBound(MyArray))
Run Code Online (Sandbox Code Playgroud)


Pro*_*fex 7

自然数(字符串)快速排序

只是为了填写主题.通常,如果您使用数字对字符串进行排序,您将获得以下内容:

    Text1
    Text10
    Text100
    Text11
    Text2
    Text20
Run Code Online (Sandbox Code Playgroud)

但是你真的希望它能够识别数值并进行排序

    Text1
    Text2
    Text10
    Text11
    Text20
    Text100
Run Code Online (Sandbox Code Playgroud)

这是怎么做的......

注意:

  • 很久以前我从网上偷了快速排序,不知道现在在哪里......
  • 我翻译了CompareNaturalNum函数,该函数最初也是用互联网编写的.
  • 与其他Q-Sorts的区别:如果BottomTemp = TopTemp,我不会交换值

自然数快速排序

Public Sub QuickSortNaturalNum(strArray() As String, intBottom As Integer, intTop As Integer)
Dim strPivot As String, strTemp As String
Dim intBottomTemp As Integer, intTopTemp As Integer

    intBottomTemp = intBottom
    intTopTemp = intTop

    strPivot = strArray((intBottom + intTop) \ 2)

    Do While (intBottomTemp <= intTopTemp)
        ' < comparison of the values is a descending sort
        Do While (CompareNaturalNum(strArray(intBottomTemp), strPivot) < 0 And intBottomTemp < intTop)
            intBottomTemp = intBottomTemp + 1
        Loop
        Do While (CompareNaturalNum(strPivot, strArray(intTopTemp)) < 0 And intTopTemp > intBottom) '
            intTopTemp = intTopTemp - 1
        Loop
        If intBottomTemp < intTopTemp Then
            strTemp = strArray(intBottomTemp)
            strArray(intBottomTemp) = strArray(intTopTemp)
            strArray(intTopTemp) = strTemp
        End If
        If intBottomTemp <= intTopTemp Then
            intBottomTemp = intBottomTemp + 1
            intTopTemp = intTopTemp - 1
        End If
    Loop

    'the function calls itself until everything is in good order
    If (intBottom < intTopTemp) Then QuickSortNaturalNum strArray, intBottom, intTopTemp
    If (intBottomTemp < intTop) Then QuickSortNaturalNum strArray, intBottomTemp, intTop
End Sub
Run Code Online (Sandbox Code Playgroud)

自然数比较(用于快速排序)

Function CompareNaturalNum(string1 As Variant, string2 As Variant) As Integer
'string1 is less than string2 -1
'string1 is equal to string2 0
'string1 is greater than string2 1
Dim n1 As Long, n2 As Long
Dim iPosOrig1 As Integer, iPosOrig2 As Integer
Dim iPos1 As Integer, iPos2 As Integer
Dim nOffset1 As Integer, nOffset2 As Integer

    If Not (IsNull(string1) Or IsNull(string2)) Then
        iPos1 = 1
        iPos2 = 1
        Do While iPos1 <= Len(string1)
            If iPos2 > Len(string2) Then
                CompareNaturalNum = 1
                Exit Function
            End If
            If isDigit(string1, iPos1) Then
                If Not isDigit(string2, iPos2) Then
                    CompareNaturalNum = -1
                    Exit Function
                End If
                iPosOrig1 = iPos1
                iPosOrig2 = iPos2
                Do While isDigit(string1, iPos1)
                    iPos1 = iPos1 + 1
                Loop

                Do While isDigit(string2, iPos2)
                    iPos2 = iPos2 + 1
                Loop

                nOffset1 = (iPos1 - iPosOrig1)
                nOffset2 = (iPos2 - iPosOrig2)

                n1 = Val(Mid(string1, iPosOrig1, nOffset1))
                n2 = Val(Mid(string2, iPosOrig2, nOffset2))

                If (n1 < n2) Then
                    CompareNaturalNum = -1
                    Exit Function
                ElseIf (n1 > n2) Then
                    CompareNaturalNum = 1
                    Exit Function
                End If

                ' front padded zeros (put 01 before 1)
                If (n1 = n2) Then
                    If (nOffset1 > nOffset2) Then
                        CompareNaturalNum = -1
                        Exit Function
                    ElseIf (nOffset1 < nOffset2) Then
                        CompareNaturalNum = 1
                        Exit Function
                    End If
                End If
            ElseIf isDigit(string2, iPos2) Then
                CompareNaturalNum = 1
                Exit Function
            Else
                If (Mid(string1, iPos1, 1) < Mid(string2, iPos2, 1)) Then
                    CompareNaturalNum = -1
                    Exit Function
                ElseIf (Mid(string1, iPos1, 1) > Mid(string2, iPos2, 1)) Then
                    CompareNaturalNum = 1
                    Exit Function
                End If

                iPos1 = iPos1 + 1
                iPos2 = iPos2 + 1
            End If
        Loop
        ' Everything was the same so far, check if Len(string2) > Len(String1)
        ' If so, then string1 < string2
        If Len(string2) > Len(string1) Then
            CompareNaturalNum = -1
            Exit Function
        End If
    Else
        If IsNull(string1) And Not IsNull(string2) Then
            CompareNaturalNum = -1
            Exit Function
        ElseIf IsNull(string1) And IsNull(string2) Then
            CompareNaturalNum = 0
            Exit Function
        ElseIf Not IsNull(string1) And IsNull(string2) Then
            CompareNaturalNum = 1
            Exit Function
        End If
    End If
End Function
Run Code Online (Sandbox Code Playgroud)

isDigit(用于CompareNaturalNum)

Function isDigit(ByVal str As String, pos As Integer) As Boolean
Dim iCode As Integer
    If pos <= Len(str) Then
        iCode = Asc(Mid(str, pos, 1))
        If iCode >= 48 And iCode <= 57 Then isDigit = True
    End If
End Function
Run Code Online (Sandbox Code Playgroud)


Nig*_*nan 6

我发布了一些代码来回答StackOverflow上的相关问题:

在VBA中对多维数组进行排序

该线程中的代码示例包括:

  1. 一个矢量数组Quicksort;
  2. 一个多列数组QuickSort;
  3. 一个BubbleSort.

Alain的优化Quicksort非常闪亮:我只是进行了基本的拆分和递归,但上面的代码示例具有"门控"功能,可以减少重复值的冗余比较.另一方面,我为Excel编写代码,并且在防御性编码方面还有一些 - 请注意,如果你的数组包含有害的'Empty()'变体,你将需要它,这会破坏你的.. .比较运算符并将代码陷入无限循环.

请注意,quicksort algorthms - 以及任何递归算法 - 可以填充堆栈并使Excel崩溃.如果你的阵列少于1024个成员,我会使用一个基本的BubbleSort.

__PRE__


Pra*_*mar 6

Dim arr As Object
Dim InputArray

'Creating a array list
Set arr = CreateObject("System.Collections.ArrayList")

'String
InputArray = Array("d", "c", "b", "a", "f", "e", "g")

'number
'InputArray = Array(6, 5, 3, 4, 2, 1)

' adding the elements in the array to array_list
For Each element In InputArray
    arr.Add element
Next

'sorting happens
arr.Sort

'Converting ArrayList to an array
'so now a sorted array of elements is stored in the array sorted_array.

sorted_array = arr.toarray
Run Code Online (Sandbox Code Playgroud)

  • @Ans 拒绝了您的编辑 - 您删除了对转换的所有评论,因此只留下未注释的代码(作为函数)。简短是好的,但在降低此答案的其他读者的“可理解性”时则不然。 (2认同)