Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Any, ByVal Source As Any, ByVal Length As Long)
Public Sub qsort(ByVal base As Long, ByVal num As Long, ByVal width As Long, ByVal compare As Long)
'排序base开始的num个元素
If num < 2 Then Exit Sub
Call sort(base, base + num * width, Int(Log(num) / Log(2)) * 2, width, compare)
End Sub
Public Sub psort(ByVal base As Long, ByVal m As Long, ByVal num As Long, ByVal width As Long, ByVal compare As Long)
'排序base开始的num个元素 保证前m个在正确的位置上
If m < 1 Or num < m Then
Exit Sub
End If
Dim n As Long, i As Long
n = m * width
For i = (m \ 2 - 1) * width To 0 Step -width
Call shiftDown(base, i, n, width, compare)
Next
Dim p As Long, hi As Long
hi = base + (num - 1) * width
For p = base + n To hi Step width
If CallWindowProc(compare, p, base, 0, 0) < 0 Then
Call swap(p, base, width)
Call shiftDown(base, 0, n, width, compare)
End If
Next
For i = n - width To width Step -width
Call swap(base, base + i, width)
Call shiftDown(base, 0, i, width, compare)
Next
End Sub
Private Sub shiftDown(ByVal base As Long, ByVal i As Long, ByVal n As Long, ByVal width As Long, ByVal compare As Long)
Dim c As Long
Do While 2 * i + width < n
c = 2 * i + width
If c < n - width Then
If CallWindowProc(compare, base + c, base + c + width, 0, 0) < 0 Then
c = c + width
End If
End If
If CallWindowProc(compare, base + i, base + c, 0, 0) >= 0 Then
Exit Do
End If
Call swap(base + i, base + c, width)
i = c
Loop
End Sub
Private Sub sort(ByVal first As Long, ByVal last As Long, ByVal depth As Long, ByVal width As Long, ByVal compare As Long)
Dim top As Long
Dim stack((8 * 4 - 2) * 3 - 1) As Long
top = 0
stack(top) = first: top = top + 1
stack(top) = last: top = top + 1
stack(top) = depth: top = top + 1
Dim cut As Long, num As Long
Do While top <> 0
top = top - 1: depth = stack(top)
top = top - 1: last = stack(top)
top = top - 1: first = stack(top)
Do
num = (last - first) \ width
If num <= 16 Then
Call insertionSort(first, last, width, compare)
Exit Do
End If
If depth = 0 Then
Call psort(first, num, num, width, compare)
Exit Do
End If
depth = depth - 1
cut = partition(first, last, median(first, first + (num \ 2) * width, last - width, compare), width, compare)
If cut - first >= last - cut Then
If first < cut Then
stack(top) = first: top = top + 1
stack(top) = cut: top = top + 1
stack(top) = depth: top = top + 1
End If
first = cut
Else
If cut < last Then
stack(top) = cut: top = top + 1
stack(top) = last: top = top + 1
stack(top) = depth: top = top + 1
End If
last = cut
End If
Loop
Loop
End Sub
Private Function partition(ByVal first As Long, ByVal last As Long, ByVal pivot As Long, ByVal width As Long, ByVal compare As Long) As Long
Do
Do While CallWindowProc(compare, first, pivot, 0, 0) < 0
first = first + width
Loop
last = last - width
Do While CallWindowProc(compare, pivot, last, 0, 0) < 0
last = last - width
Loop
If first >= last Then
partition = first
Exit Function
End If
Call swap(first, last, width)
If first = pivot Then
pivot = last
ElseIf last = pivot Then
pivot = first
End If
first = first + width
Loop
End Function
Private Function median(ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal compare As Long) As Long
If CallWindowProc(compare, a, b, 0, 0) < 0 Then
If CallWindowProc(compare, b, c, 0, 0) < 0 Then
median = b
ElseIf CallWindowProc(compare, a, c, 0, 0) < 0 Then
median = c
Else
median = a
End If
ElseIf CallWindowProc(compare, a, c, 0, 0) < 0 Then
median = a
ElseIf CallWindowProc(compare, b, c, 0, 0) < 0 Then
median = c
Else
median = b
End If
End Function
Private Sub insertionSort(ByVal first As Long, ByVal last As Long, ByVal width As Long, ByVal compare As Long)
Dim i As Long, j As Long
For i = first + width To last - width Step width
For j = i - width To first Step -width
If CallWindowProc(compare, j, j + width, 0, 0) <= 0 Then
Exit For
End If
Call swap(j, j + width, width)
Next
Next
End Sub
Private Sub swap(ByVal elem1 As Long, ByVal elem2 As Long, ByVal width As Long)
Dim t As Double, p As Long
p = VarPtr(t)
Do While width > 8
CopyMemory p, elem1, 8
CopyMemory elem1, elem2, 8
CopyMemory elem2, p, 8
elem1 = elem1 + 8
elem2 = elem2 + 8
width = width - 8
Loop
CopyMemory p, elem1, width
CopyMemory elem1, elem2, width
CopyMemory elem2, p, width
End Sub
Public Function comp(ByVal elem1 As Long, ByVal elem2 As Long, ByVal p1 As Long, ByVal p2 As Long) As Long
'回调函数写法1
Dim a As Long, b As Long
CopyMemory VarPtr(a), elem1, 4
CopyMemory VarPtr(b), elem2, 4
If a < b Then
comp = -1
ElseIf a > b Then
comp = 1
Else
comp = 0
End If
End Function
Public Function comp1(ByRef elem1 As Long, ByRef elem2 As Long, ByVal p1 As Long, ByVal p2 As Long) As Long