Thread: Sorting
View Single Post
  #6  
Old 05-15-2003, 05:59 PM
Squirm's Avatar
Squirm Squirm is offline
Political Coder

Retired Moderator
* Guru *
 
Join Date: Mar 2001
Location: London, England
Posts: 8,037
Talking Merge Sort

Merge Sort
At a first glance the merge sort appears to be identical to the quick sort. However, rather than separating the values into distinct left and right groups, we simply sort them straight away with no pivot values. The value comparisons are done when we come to merge the two sorts together, but since the groups are ordered, we need only compare the smallest of one group with the smallest of the other.

Example:
Code:
Array of data [2,8,4,9,3,5,7,1,0,6]

       [2,8,4,9,3,5,7,1,0,6]
         |               |             Recursive step
   [2,8,4,9,3]       [5,7,1,0,6]
    |       |         |       |        Recursive step
  [2,8]  [4,9,3]    [5,7]  [1,0,6]
    |     |   |       |     |   |      Recursive step
  [2,8]  [4][3,9]   [5,7]  [1][0,6]
    |     |   |       |     |   |      Merge step
  [2,8]  [3,4,9]    [5,7]  [0,1,6]
    |       |         |       |        Merge step
   [2,3,4,8,9]       [0,1,5,6,7]
         |               |             Merge step
       [0,1,2,3,4,5,6,7,8,9]

Finish [0,1,2,3,4,5,6,7,8,9]
The merge sort is different in other ways. For one, it requires a second array to hold the data, as we merge from one into the other. Another difference is that it can easily be implemented non-recursively, as I have done in the code below. The MergeSort procedure calls the InnerMergePass sub with larger and larger segment sizes.

Code:
Public Sub MergeSort(ByRef lngArray() As Long) Dim arrTemp() As Long Dim iSegSize As Long Dim iLBound As Long Dim iUBound As Long iLBound = LBound(lngArray) iUBound = UBound(lngArray) ReDim arrTemp(iLBound To iUBound) iSegSize = 1 Do While iSegSize < iUBound - iLBound 'Merge from A to B InnerMergePass lngArray, arrTemp, iLBound, iUBound, iSegSize iSegSize = iSegSize + iSegSize 'Merge from B to A InnerMergePass arrTemp, lngArray, iLBound, iUBound, iSegSize iSegSize = iSegSize + iSegSize Loop End Sub Private Sub InnerMergePass(ByRef lngSrc() As Long, ByRef lngDest() As Long, ByVal iLBound As Long, iUBound As Long, ByVal iSegSize As Long) Dim iSegNext As Long iSegNext = iLBound Do While iSegNext <= iUBound - (2 * iSegSize) 'Merge 2 segments from src to dest InnerMerge lngSrc, lngDest, iSegNext, iSegNext + iSegSize - 1, iSegNext + iSegSize + iSegSize - 1 iSegNext = iSegNext + iSegSize + iSegSize Loop 'Fewer than 2 full segments remain If iSegNext + iSegSize <= iUBound Then '2 segs remain InnerMerge lngSrc, lngDest, iSegNext, iSegNext + iSegSize - 1, iUBound Else '1 seg remains, just copy it For iSegNext = iSegNext To iUBound lngDest(iSegNext) = lngSrc(iSegNext) Next iSegNext End If End Sub Private Sub InnerMerge(ByRef lngSrc() As Long, ByRef lngDest() As Long, ByVal iStartFirst As Long, ByVal iEndFirst As Long, ByVal iEndSecond As Long) Dim iFirst As Long Dim iSecond As Long Dim iResult As Long Dim iOuter As Long iFirst = iStartFirst iSecond = iEndFirst + 1 iResult = iStartFirst Do While (iFirst <= iEndFirst) And (iSecond <= iEndSecond) 'Select the smaller value and place in the output 'Since the subarrays are already sorted, only one comparison is needed If lngSrc(iFirst) <= lngSrc(iSecond) Then lngDest(iResult) = lngSrc(iFirst) iFirst = iFirst + 1 Else lngDest(iResult) = lngSrc(iSecond) iSecond = iSecond + 1 End If iResult = iResult + 1 Loop 'Take care of any leftover values If iFirst > iEndFirst Then 'Got some leftover seconds For iOuter = iSecond To iEndSecond lngDest(iResult) = lngSrc(iOuter) iResult = iResult + 1 Next iOuter Else 'Got some leftover firsts For iOuter = iFirst To iEndFirst lngDest(iResult) = lngSrc(iOuter) iResult = iResult + 1 Next iOuter End If End Sub
__________________
Search the forums | Use [vb][/vb] tags | Still IRCing

Last edited by herilane; 04-14-2005 at 07:36 AM. Reason: Corrected typo in code
Reply With Quote