‘ Iterative QuickSort algorithm
Sub SortArray(aTarget() As Variant, Optional vFirst As Variant, _
Optional vLast As Variant, Optional helper As ISortHelper)
Dim iFirst As Long, iLast As Long
If IsMissing(vFirst) Then iFirst = LBound(aTarget) Else iFirst = vFirst
If IsMissing(vLast) Then iLast = UBound(aTarget) Else iLast = vLast
If helper Is Nothing Then Set helper = New CSortHelper
With helper
Dim iLo As Long, iHi As Long, iRand As Long, stack As New CStack
Do
Do
‘ Swap from ends until first and last meet in the middle
If iFirst < iLast Then
‘ If we’re in the middle and out of order, swap
If iLast - iFirst = 1 Then
If .Compare(aTarget(iFirst), aTarget(iLast)) > 0 Then
.Swap aTarget(iFirst), aTarget(iLast)
End If
Else
‘ Split at some random point
.Swap aTarget(iLast), _
aTarget(MRandom.Random(iFirst, iLast))
‘ Swap high values below the split for low values above
iLo = iFirst: iHi = iLast
Do
‘ Find any low value larger than split
Do While (iLo < iHi) And _
(.Compare(aTarget(iLo), aTarget(iLast)) <= 0)
iLo = iLo + 1
Loop
‘ Find any high value smaller than split
Do While (iHi > iLo) And _
(.Compare(aTarget(iHi), aTarget(iLast)) >= 0)
iHi = iHi - 1
Loop
‘ Swap too high low value for too low high value
If iLo < iHi Then .Swap aTarget(iLo), aTarget(iHi)
Loop While iLo < iHi
‘ Current (iLo) is larger than split (iLast), so swap
.Swap aTarget(iLo), aTarget(iLast)
‘ Push range markers of larger part for later sorting
If (iLo - iFirst) < (iLast - iLo) Then
stack.Push iLo + 1
stack.Push iLast
iLast = iLo - 1
Else
stack.Push iFirst
stack.Push iLo - 1
iFirst = iLo + 1
End If
‘ Exit from inner loop to process smaller part
Exit Do
End If
End If
‘ If stack empty, Exit outer loop
If stack.Count = 0 Then Exit Sub
‘ Else pop first and last from last deferred section
iLast = stack.Pop
iFirst = stack.Pop
Loop
Loop
End With
End Sub
I’m embarrassed to admit that the recursive version of this algorithm in the first edition contained an example of one of the oldest and most pervasive bugs you can write. It made several assignments inside a loop that could just as easily have been made outside the loop. As a result, the function was four to five times slower than necessary. Sharp-eyed reader David Wilmer identified the problem. To make matters worse, the same bug actually showed up in five different places on the CD. I reported the problem and provided a fix (with abject apologies) on the Internet site for the book, but some readers might have missed it. My only excuse (a weak one) is that it wasn’t originally my bug. The code came from an old version of SORTDEMO, but I learned later that the bug and the fix were described years ago in the Knowledge Base for QuickBasic. I don’t spend a lot of time wandering through bug reports in defunct products, so I missed it. Sorry about that.