MergeSort for Double Arrays

Hello There =)

I made a MergeSort function for matrices with Double Data. I haven't found this on the web (one that works, that is), so I'm posting here, so ppl can watch, and maybe improve.

To use with strings and other kinds of variables, you just have to change the compare statement, and the type (Double). The compare statements are bolded.

Cya

Public Function MergeSort(Doubles() As Double) As Double()

Dim s As Long, i As Long, n() As Double, m() As Double
Dim u As Long, l As Long, j As Long, x() As Double

' Only 1 element
If (UBound(Doubles) - LBound(Doubles)) = 0 Then
MergeSort = Doubles
Exit Function

' Only 2 elements
ElseIf (UBound(Doubles) - LBound(Doubles)) = 1 Then
MergeSort = Ordena2(Doubles)
Exit Function
Else
SplitArray Doubles, m, n
m = MergeSort(m)
n = MergeSort(n)
MergeSort = MergeArray(m, n)
End If
End Function

Private Sub SplitArray(Doubles() As Double, _
DoubleOut1() As Double, DoubleOut2() As Double)

Dim meio, pos_Doubles, pos_Quebrado As Long
Dim z As Long

If (UBound(Doubles) - LBound(Doubles)) = 0 Then
Exit Sub
End If

meio = Int((UBound(Doubles) - LBound(Doubles)) / 2)

pos_Quebrado = 0
For pos_Doubles = 0 To (meio - 1)
ReDim Preserve DoubleOut1(pos_Quebrado)
DoubleOut1(pos_Quebrado) = Doubles(pos_Doubles)
pos_Quebrado = pos_Quebrado + 1
Next

pos_Quebrado = 0
For pos_Doubles = meio To UBound(Doubles)
ReDim Preserve DoubleOut2(pos_Quebrado)
DoubleOut2(pos_Quebrado) = Doubles(pos_Doubles)
pos_Quebrado = pos_Quebrado + 1
Next
End Sub

Private Function MergeArray(Double1() As Double, _
Double2() As Double) As Double()
Dim pos1, pos2 As Long
Dim Array_Final() As Double
'Check if Double1 or Double2 are empty
On Error Resume Next
If IsEmpty(Double1(0)) Then
MergeArray = Double2
Exit Function
ElseIf IsEmpty(Double2(0)) Then
MergeArray = Double1
Exit Function
End If
ReDim Array_Final((UBound(Double1) - LBound(Double1) + 1) + (UBound(Double2) - LBound(Double2) + 1) - 1)
pos1 = LBound(Double1)
pos2 = LBound(Double2)
Do Until pos1 > UBound(Double1) Or pos2 > UBound(Double2)
Do While (pos1 <= UBound(Double1) And pos2 <= UBound(Double2))
If Double1(pos1) <= Double2(pos2) Then
Array_Final(pos1 + pos2) = Double1(pos1)
pos1 = pos1 + 1
Else
Exit Do
End If
Loop
Do While (pos1 <= UBound(Double1) And pos2 <= UBound(Double2))
If Double2(pos2) <= Double1(pos1) Then
Array_Final(pos1 + pos2) = Double2(pos2)
pos2 = pos2 + 1
Else
Exit Do
End If
Loop
Loop
'Finaliza o Merge
If pos1 > UBound(Double1) Then
Do Until pos2 > UBound(Double2)
Array_Final(pos1 + pos2) = Double2(pos2)
pos2 = pos2 + 1
Loop
Else ' pos2 > UBound(Double2)
Do Until pos1 > UBound(Double1)
Array_Final(pos1 + pos2) = Double1(pos1)
pos1 = pos1 + 1
Loop
End If
MergeArray = Array_Final
End Function

Public Function Sort2(Doubles() As Double) As Double()

'Comes here when there's only 2 elements to sort
Dim temp As Double
If Doubles(0) > Doubles(1) Then
temp = Doubles(0)
Doubles(0) = Doubles(1)
Doubles(1) = temp
End If
Sort2= Doubles
End Function



Answer this question

MergeSort for Double Arrays

  • Sameep

    Hi,

    Can you post the function Ordena2.

    Also a example of how to use the function(s) would be nice ;)


  • praveench2k

    Hehe, sorry, I translated a few parts, and forgot others. =]

    To use the MergeSort you just have to pass the vector, like this:

    Dim Original_Vector(), Sorted_Vector As Double

    Sorted_Vector = MergeSort(Original_Vector)

    That way you preserve the original vector, and put the sorted one in another variable. If you want to just sort the vector, do like this:

    Original_Vector = MergeSort(Original_Vector)

    This was made specially for one-dimension arrays. It won't work for two dimensions or more. This time I deleted some junk, parts of the merges I was trying, before developing my own.

    Public Function MergeSort(Doubles() As Double) As Double()

    Dim Left() As Double, Right() As Double

    ' Only 1 element
    If (UBound(Doubles) - LBound(Doubles)) = 0 Then
    MergeSort = Doubles
    Exit Function

    ' Only 2 elements
    ElseIf (UBound(Doubles) - LBound(Doubles)) = 1 Then
    MergeSort = Sort2(Doubles)
    Exit Function
    Else
    SplitArray Doubles, Left, Right 'Divide to conquer >:)
    m = MergeSort(m) 'Call MergeSort on the small parts of the original vector
    n = MergeSort(n) ' same here
    MergeSort = MergeArray(m, n) ' At the end, merge the
    End If
    End Function

    Private Sub SplitArray(Doubles() As Double, _
    DoubleOut1() As Double, DoubleOut2() As Double)

    ' Because DoubleOut1 and 2, as well Doubles are passed ByRef, the changes here affect the original ones too.

    Dim middle, pos_Doubles, pos_Quebrado As Long

    middle= Int((UBound(Doubles) - LBound(Doubles)) / 2)

    pos_Quebrado = 0
    For pos_Doubles = 0 To (middle - 1)
    ReDim Preserve DoubleOut1(pos_Quebrado)
    DoubleOut1(pos_Quebrado) = Doubles(pos_Doubles)
    pos_Quebrado = pos_Quebrado + 1
    Next

    pos_Quebrado = 0
    For pos_Doubles = middle To UBound(Doubles)
    ReDim Preserve DoubleOut2(pos_Quebrado)
    DoubleOut2(pos_Quebrado) = Doubles(pos_Doubles)
    pos_Quebrado = pos_Quebrado + 1
    Next
    End Sub

    Private Function MergeArray(Double1() As Double, Double2() As Double) As Double()
    Dim pos1, pos2 As Long
    Dim Array_Final() As Double
    'Check if Double1 or Double2 are empty
    On Error Resume Next
    If IsEmpty(Double1(0)) Then
    MergeArray = Double2
    Exit Function
    ElseIf IsEmpty(Double2(0)) Then
    MergeArray = Double1
    Exit Function
    End If
    ReDim Array_Final((UBound(Double1) - LBound(Double1) + 1) + (UBound(Double2) - LBound(Double2) + 1) - 1)

    'Set the inicial positions as the lower indexes of Double1 and Double2
    pos1 = LBound(Double1)
    pos2 = LBound(Double2)

    'While the indexes are "inside" the vectors, you search for the lower one
    Do Until pos1 > UBound(Double1) Or pos2 > UBound(Double2)
    Do While (pos1 <= UBound(Double1) And pos2 <= UBound(Double2))
    If Double1(pos1) <= Double2(pos2) Then
    Array_Final(pos1 + pos2) = Double1(pos1)
    pos1 = pos1 + 1
    Else
    Exit Do
    End If
    Loop
    Do While (pos1 <= UBound(Double1) And pos2 <= UBound(Double2))
    If Double2(pos2) <= Double1(pos1) Then
    Array_Final(pos1 + pos2) = Double2(pos2)
    pos2 = pos2 + 1
    Else
    Exit Do
    End If
    Loop
    Loop
    'Finish the merge, because one of the vectors didn't go until the end.
    If pos1 > UBound(Double1) Then
    Do Until pos2 > UBound(Double2)
    Array_Final(pos1 + pos2) = Double2(pos2)
    pos2 = pos2 + 1
    Loop
    Else ' pos2 > UBound(Double2)
    Do Until pos1 > UBound(Double1)
    Array_Final(pos1 + pos2) = Double1(pos1)
    pos1 = pos1 + 1
    Loop
    End If
    MergeArray = Array_Final
    End Function

    Public Function Sort2(Doubles() As Double) As Double()

    'Comes here when there's only 2 elements to sort
    Dim temp As Double
    If Doubles(0) > Doubles(1) Then
    temp = Doubles(0)
    Doubles(0) = Doubles(1)
    Doubles(1) = temp
    End If
    Sort2= Doubles
    End Function


  • Benedikt

    One change you can make to speed things a little is to move the Redim out of the loops in the SplitArray routine.

    Sub Tester()

    Dim Original_Vector() As Double
    Dim Sorted_Vector() As Double
    Dim lngIndex As Long
    Const MAX_ELEMENTS = 50 '

    ReDim Original_Vector(MAX_ELEMENTS)
    For lngIndex = 1 To MAX_ELEMENTS
    Original_Vector(lngIndex) = Rnd() * MAX_ELEMENTS
    Next

    Sorted_Vector = MergeSort(Original_Vector)

    End Sub
    Public Function MergeSort(Doubles() As Double) As Double()

    Dim Left() As Double, Right() As Double

    ' Only 1 element
    If (UBound(Doubles) - LBound(Doubles)) = 0 Then
    MergeSort = Doubles
    Exit Function

    ' Only 2 elements
    ElseIf (UBound(Doubles) - LBound(Doubles)) = 1 Then
    MergeSort = Sort2(Doubles)
    Exit Function
    Else
    NewSplitArray Doubles, Left, Right 'Divide to conquer >:)
    Left = MergeSort(Left) 'Call MergeSort on the small parts of the original vector
    Right = MergeSort(Right) ' same here
    MergeSort = MergeArray(Left, Right) ' At the end, merge the
    End If

    End Function

    Private Sub NewSplitArray(Doubles() As Double, _
    DoubleOut1() As Double, DoubleOut2() As Double)

    ' Because DoubleOut1 and 2, as well Doubles are passed ByRef, the changes here affect the original ones too.

    Dim middle, pos_Doubles, pos_Quebrado As Long

    middle = Int((UBound(Doubles) - LBound(Doubles)) / 2)

    pos_Quebrado = 0
    ' Moved out of loop so resize happens only once
    ReDim DoubleOut1(middle - 1)
    For pos_Doubles = 0 To (middle - 1)
    DoubleOut1(pos_Quebrado) = Doubles(pos_Doubles)
    pos_Quebrado = pos_Quebrado + 1
    Next

    pos_Quebrado = 0
    ReDim DoubleOut2(UBound(Doubles) - middle)
    For pos_Doubles = middle To UBound(Doubles)
    DoubleOut2(pos_Quebrado) = Doubles(pos_Doubles)
    pos_Quebrado = pos_Quebrado + 1
    Next
    End Sub

    Private Function MergeArray(Double1() As Double, Double2() As Double) As Double()
    Dim pos1, pos2 As Long
    Dim Array_Final() As Double

    'Check if Double1 or Double2 are empty
    On Error Resume Next

    ' Test works on Variants not Double as these will always be FALSE
    ''' If IsEmpty(Double1(0)) Then
    ''' MergeArray = Double2
    ''' Exit Function
    ''' ElseIf IsEmpty(Double2(0)) Then
    ''' MergeArray = Double1
    ''' Exit Function
    ''' End If

    ReDim Array_Final((UBound(Double1) - LBound(Double1) + 1) + (UBound(Double2) - LBound(Double2) + 1) - 1)

    'Set the inicial positions as the lower indexes of Double1 and Double2
    pos1 = LBound(Double1)
    pos2 = LBound(Double2)

    'While the indexes are "inside" the vectors, you search for the lower one
    Do Until pos1 > UBound(Double1) Or pos2 > UBound(Double2)
    Do While (pos1 <= UBound(Double1) And pos2 <= UBound(Double2))
    If Double1(pos1) <= Double2(pos2) Then
    Array_Final(pos1 + pos2) = Double1(pos1)
    pos1 = pos1 + 1
    Else
    Exit Do
    End If
    Loop
    Do While (pos1 <= UBound(Double1) And pos2 <= UBound(Double2))
    If Double2(pos2) <= Double1(pos1) Then
    Array_Final(pos1 + pos2) = Double2(pos2)
    pos2 = pos2 + 1
    Else
    Exit Do
    End If
    Loop
    Loop
    'Finish the merge, because one of the vectors didn't go until the end.
    If pos1 > UBound(Double1) Then
    Do Until pos2 > UBound(Double2)
    Array_Final(pos1 + pos2) = Double2(pos2)
    pos2 = pos2 + 1
    Loop
    Else ' pos2 > UBound(Double2)
    Do Until pos1 > UBound(Double1)
    Array_Final(pos1 + pos2) = Double1(pos1)
    pos1 = pos1 + 1
    Loop
    End If
    MergeArray = Array_Final

    End Function

    Public Function Sort2(Doubles() As Double) As Double()

    'Comes here when there's only 2 elements to sort
    Dim temp As Double
    If Doubles(0) > Doubles(1) Then
    temp = Doubles(0)
    Doubles(0) = Doubles(1)
    Doubles(1) = temp
    End If
    Sort2 = Doubles

    End Function




  • MergeSort for Double Arrays