| ||
| Note: You can skip the following instructions and Download the Project (7K). | ||
| ||
| ||
Option Explicit
'=======================================================
' Declarations for the Timing API Call
'=======================================================
Const TIME_MS = 1
Private Type SMPTE
hour As Byte
min As Byte
sec As Byte
frame As Byte
fps As Byte
dummy As Byte
pad(2) As Byte
End Type
Private Type MMTIME
wType As Long
units As Long
smpteVal As SMPTE
songPtrPos As Long
End Type
Private Declare Function timeGetSystemTime& _
Lib "winmm.dll" (lpTime As MMTIME, ByVal uSize&)
Dim mmt As MMTIME, L1&
'=======================================================
' Other Form Level Declarations
'=======================================================
Const BUTTONS% = 4
Const MAXFUNC% = 13
Const IHI% = 32766
Const ELEMENTS% = 1000
Const UNIT! = 300, MARGIN! = 100
Const TITLEBAR! = 295, BOARDER! = 60
Const ORANGE& = &H80C0FF
Const ICL$ = "Include"
Dim ascend As Boolean
Dim last1%, confirmtotal&
Dim sorts$(MAXFUNC), captions$(3)
Dim startarray%(IHI), sortarray%(IHI)
'=======================================================
' The Sort Routines
'=======================================================
Private Sub Bubble_Sort(ByVal lower%, ByVal upper%)
Dim j%, tmp%, Done As Boolean
Do While Not Done
Done = True
upper = upper - 1
For j = lower To upper
If (ascend And _
(sortarray(j) > sortarray(j + 1))) Or _
(Not ascend And _
(sortarray(j) < sortarray(j + 1))) Then
tmp = sortarray(j)
sortarray(j) = sortarray(j + 1)
sortarray(j + 1) = tmp
Done = False
End If
Next
Loop
End Sub
'The Bubble done with a shuffle up
'Rather than the classic method of swapping with the
' next contiguous element of an array, a SHUFFLE
' keeps the initial element as a tmp and then makes
' tests incrementally with next elements (making
' single assignments along the way) until it arrives
' at the spot where it normally be swapped to and
' at that place the tmp is deposited. There can be
' significant time savings (especially seen in the
' Insertion Sort below) because with each swap three
' assignments are required, whereas only one is
' required when shuffling.
Private Sub Bubble2_Sort(ByVal lower%, ByVal upper%)
Dim low%, high%, tmp%, Done As Boolean
Do While Not Done
Done = True
low = lower
upper = upper - 1
Do Until low > upper
tmp = sortarray(low)
Do
high = low + 1
If (ascend And _
sortarray(high) >= tmp) Or _
(Not ascend And _
sortarray(high) <= tmp) Then Exit Do
sortarray(low) = sortarray(high)
low = high
Loop Until low > upper
If sortarray(low) <> tmp Then
sortarray(low) = tmp
Done = False
End If
low = high
Loop
Loop
End Sub
Private Sub BiBubble_Sort(ByVal lower%, ByVal upper%)
Dim j%, tmp%, Done As Boolean
Do While Not Done
Done = True
upper = upper - 1
For j = lower To upper
If (ascend And _
(sortarray(j) > sortarray(j + 1))) Or _
(Not ascend And _
(sortarray(j) < sortarray(j + 1))) Then
tmp = sortarray(j)
sortarray(j) = sortarray(j + 1)
sortarray(j + 1) = tmp
Done = False
End If
Next
If Done Then Exit Do
lower = lower + 1
For j = upper To lower Step -1
If (ascend And _
(sortarray(j) < sortarray(j - 1))) Or _
(Not ascend And _
(sortarray(j) > sortarray(j - 1))) Then
tmp = sortarray(j)
sortarray(j) = sortarray(j - 1)
sortarray(j - 1) = tmp
Done = False
End If
Next
Loop
End Sub
'The Bi-Bubble done with a shuffle up
Private Sub BiBubble2_Sort(ByVal lower%, ByVal upper%)
Dim low%, high%, tmp%, Done As Boolean
Do While Not Done
Done = True
low = lower
upper = upper - 1
Do Until low > upper
tmp = sortarray(low)
Do
high = low + 1
If (ascend And _
sortarray(high) >= tmp) Or _
(Not ascend And _
sortarray(high) <= tmp) Then Exit Do
sortarray(low) = sortarray(high)
low = high
Loop Until low > upper
If sortarray(low) <> tmp Then
sortarray(low) = tmp
Done = False
End If
low = high
Loop
If Done Then Exit Do
high = upper
lower = lower + 1
Do Until lower > high
tmp = sortarray(high)
Do
low = high - 1
If (ascend And _
sortarray(low) <= tmp) Or _
(Not ascend And _
sortarray(low) >= tmp) Then Exit Do
sortarray(high) = sortarray(low)
high = low
Loop Until lower > high
If sortarray(high) <> tmp Then
sortarray(high) = tmp
Done = False
End If
high = low
Loop
Loop
End Sub
Private Sub Insertion_Sort(ByVal lower%, ByVal upper%)
Dim j%, low%, high%, tmp%
For j = lower + 1 To upper
high = j
Do
low = high - 1
If (ascend And _
(sortarray(low) > sortarray(high))) Or _
(Not ascend And _
(sortarray(low) < sortarray(high))) Then
tmp = sortarray(low)
sortarray(low) = sortarray(high)
sortarray(high) = tmp
high = low
Else
Exit Do
End If
Loop Until high <= lower
Next
End Sub
'The Insertion done with a shuffle down
Private Sub Insertion2_Sort(ByVal lower%, ByVal upper%)
Dim j%, low%, high%, tmp%
For j = lower + 1 To upper
high = j
tmp = sortarray(high)
Do
low = high - 1
If (ascend And sortarray(low) <= tmp) Or _
(Not ascend And sortarray(low) >= tmp) _
Then Exit Do
sortarray(high) = sortarray(low)
high = low
Loop Until high <= lower
sortarray(high) = tmp
Next
End Sub
Private Sub Shell_Sort(ByVal lower%, ByVal upper%)
Dim diff%, low%, high%, tmp%
diff = Int(CSng(upper - lower) / 1.3)
Do While diff
high = lower + diff
Do Until high > upper
low = high - diff
If (ascend And _
(sortarray(low) > sortarray(high))) Or _
(Not ascend And _
(sortarray(low) < sortarray(high))) Then
tmp = sortarray(low)
sortarray(low) = sortarray(high)
sortarray(high) = tmp
If diff = 1 Then
If (low - diff) >= lower Then
'Note: attempting a shuffle down
' here doesn't improve speed
high = low - 1
End If
End If
End If
high = high + 1
Loop
diff = Int(CSng(diff) / 1.3)
Loop
End Sub
Private Sub Count_Sort(ByVal lower%, ByVal upper%)
Dim j%, incdec%
ReDim cnt%(IHI)
For j = lower To upper
cnt(sortarray(j)) = cnt(sortarray(j)) + 1
Next
j = 0
If ascend Then
incdec = 1
Else
incdec = lower
lower = upper
upper = -incdec
incdec = -1
End If
Do Until lower * incdec > upper
Do Until cnt(j) <> 0
j = j + 1
Loop
Do While cnt(j)
sortarray(lower) = j
lower = lower + incdec
cnt(j) = cnt(j) - 1
Loop
Loop
End Sub
Private Sub Selection_Sort(ByVal lower%, ByVal upper%, _
Optional interpolating As Boolean)
Dim j%, low%, high%, tmp%
Do Until lower >= upper
high = upper
low = lower
For j = lower To upper
If (ascend And _
(sortarray(j) < sortarray(low))) Or _
(Not ascend And _
(sortarray(j) > sortarray(low))) Then
low = j
ElseIf (ascend And _
(sortarray(j) > sortarray(high))) Or _
(Not ascend And _
(sortarray(j) < sortarray(high))) Then
high = j
End If
Next
If high <> upper Then
If low = upper Then low = high
tmp = sortarray(upper)
sortarray(upper) = sortarray(high)
sortarray(high) = tmp
End If
If low <> lower Then
tmp = sortarray(lower)
sortarray(lower) = sortarray(low)
sortarray(low) = tmp
End If
'When called from the interpolation sort
' just one pass is necessary to set the ends
If interpolating Then Exit Do
lower = lower + 1
upper = upper - 1
Loop
End Sub
'Kind of clumsy using one pass of a Selection Sort to
' set the ends (and the formula for the interpolation)
' and then cleaning up with and Insertion Sort -
' But with all these components it is speedy
Private Sub Interpolate_Sort(ByVal lower%, ByVal upper%)
'First set the min and max at the ends
Selection_Sort lower, upper, True
ReDim previous%(lower To upper)
Dim j%, k%, base%, offset%, dif1!, dif2!, tmp%, try%
dif1 = CSng(upper - lower)
dif2 = CSng(sortarray(upper) - sortarray(lower))
base = IIf(ascend, lower, upper)
j = lower + 1
Do Until j >= upper
If previous(j) = 0 Then
offset = base + CInt(dif1 * _
CSng(sortarray(j) - sortarray(base)) / dif2)
try = 1
Do
If offset <= lower Then
offset = lower + 1
ElseIf offset >= upper Then
offset = upper - 1
End If
If previous(offset) = 0 Then
If j <> offset Then
tmp = sortarray(j)
sortarray(j) = sortarray(offset)
sortarray(offset) = tmp
End If
previous(offset) = -1
Exit Do
ElseIf try = 1 Then
offset = offset + 1
try = 2
ElseIf try = 2 Then
offset = offset - 2
try = 3
Else
j = j + 1
Exit Do
End If
Loop
Else
j = j + 1
End If
Loop
'Cleanup imprecision and duplicates
Insertion2_Sort lower, upper
End Sub
Private Sub Merge_Sort(ByVal lower%, ByVal upper%)
Dim tmp%
Select Case upper - lower
Case Is <= 0: Exit Sub
Case 1
If (ascend And _
(sortarray(lower) > sortarray(upper))) _
Or (Not ascend And _
(sortarray(lower) < sortarray(upper))) Then
tmp = sortarray(lower)
sortarray(lower) = sortarray(upper)
sortarray(upper) = tmp
End If
Exit Sub
End Select
Dim upper1%, lower1%
upper1 = lower + (upper - lower) \ 2
lower1 = upper1 + 1
Merge_Sort lower, upper1
Merge_Sort lower1, upper
Dim ux%, uy%
Do While lower1 <= upper And lower <= upper1
If (ascend And _
(sortarray(lower) > sortarray(lower1))) Or _
(Not ascend And _
(sortarray(lower) < sortarray(lower1))) Then
tmp = sortarray(lower)
sortarray(lower) = sortarray(lower1)
'Now do a shuffle up
ux = lower1
Do Until ux >= upper
uy = ux + 1
If (ascend And _
(tmp <= sortarray(uy))) Or _
(Not ascend And _
(tmp >= sortarray(uy))) Then Exit Do
sortarray(ux) = sortarray(uy)
ux = ux + 1
Loop
sortarray(ux) = tmp
End If
lower = lower + 1
Loop
End Sub
Private Sub Quick_Sort(ByVal lower%, ByVal upper%)
If lower >= upper Then Exit Sub
Dim low%, midl%, high%, midval%, tmp%
low = lower
high = upper
midl = lower + (upper - lower) \ 2
midval = sortarray(midl)
Do While low <= high
Do Until low >= upper
If (ascend And _
sortarray(low) >= midval) Or _
(Not ascend And _
sortarray(low) <= midval) Then Exit Do
low = low + 1
Loop
Do Until high <= lower
If (ascend And _
midval >= sortarray(high)) Or _
(Not ascend And _
midval <= sortarray(high)) Then Exit Do
high = high - 1
Loop
If low <= high Then
If low < high Then
tmp = sortarray(low)
sortarray(low) = sortarray(high)
sortarray(high) = tmp
End If
low = low + 1
high = high - 1
End If
Loop
If lower < high Then Quick_Sort lower, high
If low < upper Then Quick_Sort low, upper
End Sub
Private Sub Heap_Sort(ByVal lower%, ByVal upper%)
Dim j%, tmp%
j = upper - (upper - lower) \ 2
Do Until j >= upper
SiftUp upper, j, lower
j = j + 1
Loop
For j = lower To upper - 1
If (ascend And _
(sortarray(upper) < sortarray(j))) Or _
(Not ascend And _
(sortarray(upper) > sortarray(j))) Then
tmp = sortarray(upper)
sortarray(upper) = sortarray(j)
sortarray(j) = tmp
SiftUp upper, upper - 1, j
End If
Next
End Sub
Private Sub SiftUp(first%, ByVal midl%, last%)
Dim k&, k1%, m1%, tmp%
k = CLng(midl - first) * 2 + first
Do While k >= last
If k > last Then
k1 = k + 1
If (ascend And _
(sortarray(k) < sortarray(k1))) Or _
(Not ascend And _
(sortarray(k) > sortarray(k1))) Then
k = k - 1
End If
End If
k1 = k + 1
m1 = midl + 1
If (ascend And _
(sortarray(k1) < sortarray(m1))) Or _
(Not ascend And _
(sortarray(k1) > sortarray(m1))) Then
tmp = sortarray(k1)
sortarray(k1) = sortarray(m1)
sortarray(m1) = tmp
Else
Exit Do
End If
midl = k
k = CLng(midl - first) * 2 + first
Loop
End Sub
'=======================================================
' Button Procedures
'=======================================================
Private Sub Command1_MouseUp(Index%, _
Button%, Shift%, X!, Y!)
Select Case Index
Case 0: Reset Button
Case 1: UpDn Index
Case 2: DoTimings
Case 3: IncALL
Case Else: Toggle Index, Button
End Select
End Sub
Private Sub Reset(ByVal b%)
Static i%, j%, s!
Static b1%
ChangeColor ORANGE
MousePointer = vbHourglass
DoEvents
If b = 0 Then b = b1
s = CSng(last1 + 1)
If b = 1 Then
For i = 0 To last1
Randomize
startarray(i) = Int(s * Rnd)
Next
Else
For i = 0 To last1
sortarray(i) = i
startarray(i) = -1
Next
For i = 0 To last1
Randomize
j = Int(s * Rnd)
Do While startarray(j) >= 0
j = j + 1
If j > last1 Then j = 0
Loop
startarray(j) = sortarray(i)
Next
End If
ChangeColor vbButtonShadow
b1 = b
MousePointer = vbDefault
End Sub
Private Sub ChangeColor(ByVal clr&)
Static i%
For i = 0 To MAXFUNC * 3 + 3
Label1(i).BackColor = clr
Next
Form1.BackColor = clr
DoEvents
End Sub
Private Sub UpDn(ByVal i%)
With Command1(i)
If ascend Then
.Caption = "Descend"
.ToolTipText = "Click for Ascending"
ascend = False
Else
.Caption = "Ascend"
.ToolTipText = "Click for Descending"
ascend = True
End If
End With
End Sub
Private Sub IncALL()
Dim i%
For i = BUTTONS To MAXFUNC + BUTTONS - 1
Command1(i).Caption = ICL
Next
End Sub
Private Sub Toggle(ByVal i%, ByVal b%)
Static j%, s$
s = ICL
If b = 1 Then
If Command1(i).Caption = ICL Then s = "Exclude"
Else
For j = BUTTONS To MAXFUNC + BUTTONS - 1
Command1(j).Caption = "Exclude"
Next
End If
Command1(i).Caption = s
End Sub
Private Sub DoTimings()
Static i%, func%, t1&, t2&
Static lower%, upper%
Static flag As Boolean
Screen.MousePointer = vbHourglass
ChangeColor vbButtonShadow
For lower = MAXFUNC To MAXFUNC * 3 - 1
Label1(lower).Caption = ""
Next
confirmtotal = 0
For i = 0 To last1
confirmtotal = confirmtotal + startarray(i)
Next
lower = 0: upper = last1
For func = BUTTONS To MAXFUNC + BUTTONS - 1
If Command1(func).Caption = ICL Then
For i = 0 To last1
sortarray(i) = startarray(i)
Next
DoEvents
t1 = GetTime
Select Case func
Case 4: Bubble_Sort 0, last1
Case 5: Bubble2_Sort 0, last1
Case 6: BiBubble_Sort 0, last1
Case 7: BiBubble2_Sort 0, last1
Case 8: Insertion_Sort 0, last1
Case 9: Insertion2_Sort 0, last1
Case 10: Shell_Sort 0, last1
Case 11: Count_Sort 0, last1
Case 12: Selection_Sort 0, last1
Case 13: Interpolate_Sort 0, last1
Case 14: Merge_Sort 0, last1
Case 15: Quick_Sort 0, last1
Case 16: Heap_Sort 0, last1
End Select
t2 = GetTime
DoEvents
flag = ShowTime(t1, t2, func)
End If
Next
If flag Then
For lower = 0 To last1
startarray(lower) = sortarray(lower)
Next
ChangeColor ORANGE
End If
Screen.MousePointer = vbDefault
End Sub
Private Function GetTime&()
timeGetSystemTime mmt, L1
GetTime = mmt.units
End Function
Private Function ShowTime(start&, stopp&, ByVal i%) _
As Boolean
i = i - BUTTONS
Label1(i + MAXFUNC).Caption = CStr(stopp - start)
ShowTime = Confirm(i)
End Function
Private Function Confirm(ByVal i%) As Boolean
Static j%, s$
Dim l&
s = "success"
Confirm = True
l = sortarray(0)
For j = 1 To last1
l = l + sortarray(j)
If (ascend And _
(sortarray(j) < sortarray(j - 1))) Or _
(Not ascend And _
(sortarray(j) > sortarray(j - 1))) Then
s = "!order!"
Confirm = False
Exit For
End If
Next
If l <> confirmtotal Then
s = "!total!"
Confirm = False
End If
Label1(i + MAXFUNC * 2).Caption = s
End Function
'=======================================================
' Handle the TextBox for Number of Elements Input
'=======================================================
Private Sub Text1_KeyUp(KeyCode%, Shift%)
If KeyCode = vbKeyReturn Then Command1(2).SetFocus
End Sub
Private Sub Text1_LostFocus()
Dim d#, i%
d = Val(Text1.Text)
If d < 100 Or d > IHI Then
i = last1 + 1
Else
i = CInt(d)
last1 = i - 1
Reset 0
End If
Text1.Text = CStr(i)
End Sub
'=======================================================
' Initialization
'=======================================================
Private Sub Form_Load()
Const WDTH = UNIT * 3
Dim i%, j%, lt!, tp!, tp1!, w!
ascend = True
last1 = ELEMENTS - 1
mmt.wType = TIME_MS
L1 = LenB(mmt)
Height = BOARDER * 2 + TITLEBAR + _
(UNIT + MARGIN) * (MAXFUNC + 3)
Width = (MARGIN + BOARDER) * 2 + _
UNIT * 15 + MARGIN * 4
BackColor = vbButtonShadow
Caption = "Sorting Timer"
AddButton "Randomize", _
"Right click for all different numbers"
AddButton "Ascend", "Click for Descending"
AddButton "Timings", "Perform Timings"
tp = MARGIN + UNIT
lt = BOARDER + MARGIN + (MARGIN + UNIT * 4) * 3
With Text1
.Move lt, MARGIN + UNIT, WDTH, UNIT
.Text = CStr(ELEMENTS)
End With
sorts(0) = "Bubble"
sorts(1) = "Bubble2"
sorts(2) = "Bi-Bubble"
sorts(3) = "Bi-Bubble2"
sorts(4) = "Insertion"
sorts(5) = "Insertion2"
sorts(6) = "Shell"
sorts(7) = "Count"
sorts(8) = "Selection"
sorts(9) = "Interpolate"
sorts(10) = "Merge"
sorts(11) = "Quick"
sorts(12) = "Heap"
captions(0) = "Sort Type"
captions(1) = "Millisecs"
captions(2) = "Verified"
captions(3) = "Elements"
lt = BOARDER + MARGIN
tp = BOARDER + (MARGIN + UNIT) * 2
For j = 0 To MAXFUNC
i = j + 3
Load Command1(i)
With Command1(i)
.Move lt, tp, WDTH, UNIT
.FontBold = True
.Visible = True
If j Then
.Caption = ICL
.ToolTipText = "Right click for only this"
Else
.Caption = "ALL"
.ToolTipText = "Include all methods"
End If
End With
tp = tp + MARGIN + UNIT
Next
DoEvents
tp = BOARDER + MARGIN * 3 + WDTH
tp1 = tp
lt = BOARDER + MARGIN * 2 + WDTH
w = UNIT * 5
For j = 0 To MAXFUNC - 1
If j Then Load Label1(j)
With Label1(j)
.Move lt, tp, w, UNIT
.BackColor = vbButtonShadow
.Caption = sorts(j)
.FontBold = True
.Visible = True
.Alignment = 1
End With
tp = tp + MARGIN + UNIT
Next
DoEvents
tp = tp1
lt = MARGIN * 3 + UNIT * 8
w = UNIT * 4
For j = 0 To MAXFUNC - 1
i = j + MAXFUNC
Load Label1(i)
With Label1(i)
.Move lt, tp, w, UNIT
.FontBold = True
.Visible = True
.Alignment = 1
.Caption = ""
End With
tp = tp + MARGIN + UNIT
Next
DoEvents
tp = tp1
lt = BOARDER + MARGIN * 4 + UNIT * 12
For j = 0 To MAXFUNC - 1
i = j + MAXFUNC * 2
Load Label1(i)
With Label1(i)
.Move lt, tp, WDTH, UNIT
.FontBold = True
.Visible = True
.Caption = ""
End With
tp = tp + MARGIN + UNIT
Next
DoEvents
tp = MARGIN * 3 + UNIT * 2
lt = BOARDER + MARGIN * 2 + UNIT * 5
For j = 0 To 3
i = j + MAXFUNC * 3
Load Label1(i)
With Label1(i)
.Move lt, tp, WDTH, UNIT
.Caption = captions(j)
.FontBold = True
.Visible = True
.Alignment = 2
End With
Select Case j
Case 0: lt = lt + MARGIN + WDTH + UNIT
Case 2: tp = MARGIN
Case Else: lt = lt + MARGIN + WDTH
End Select
Next
DoEvents
Reset 1
End Sub
Private Sub AddButton(s$, Optional tip$ = "")
Const HT! = UNIT * 2, WD! = UNIT * 4
Static num%, j%, lt!
If num Then
Load Command1(num)
Else
lt = BOARDER + MARGIN
End If
With Command1(num)
.Move lt, MARGIN, WD, HT
.ToolTipText = tip
.FontBold = True
.Visible = True
.Caption = s
End With
lt = lt + MARGIN + UNIT * 4
num = num + 1
End Sub
| ||
| Press F5 to run the timer. Immediately you will see the Form Window pictured above and be able to time the sorts by clicking on Timings. | ||
|
Randomize
The timing uses an API call and includes no DoEvents while sorting for the most accurate timing. That means, however, that your computer will seem to lock up while sorting. While running from the VB editor, you may stop at any time by pressing [Ctrl][Break].
For elements exceeding 10,000, you may want to include just the fastest sorting methods (Count, Heap, Quick, and Shell). Refer to the my timings chart below.
Include
| ||
My timings on these methods from the VB editor on my AMD K6-450 computer:
|