maxscreenx = 1366
maxscreeny = 768
numcolors% = 256
n& = (maxscreenx * maxscreeny)
'* OpenFile t, "r", channel%, "stats.txt"
'DO
' IF i& > LOF(channel%) \ LEN(t) THEN
' EXIT DO
' ELSE
' i& = i& + 1
' GET #channel%, i&, t
' Sorts(i&) = t
' END IF
'LOOP
lastsort% = -1
SortNum = 3 'INT(RND * 19)
Sorts(SortNum).sorttocall = SortNum
HandleSort Sorts(), "QuickSort (Recursive) -- CAR Hoare", 0, n& - 1, maxscreenx
HandleSort Sorts(), "ShellSort (Metzler Variant) -- (DL Shell) with improvement by Donald Metzler and seal of approval by Donald knuth", 0, n& - 1, maxscreenx
HandleSort Sorts(), "FlashSort -- (Karl Dietrich Neubert) non-comparison sort really fast", 1, n& - 1, maxscreenx
HandleSort Sorts(), "Radix Sort -- Jon Von Neumann", 0, n& - 1, maxscreenx
HandleSort Sorts(), "Shell Sort (Original) -- (DL Shell)", 0, (n& - 1) \ 8, maxscreenx
HandleSort Sorts(), "Shell Sort (Single pass per gap - shrink factor = 1.247...) -- (DL Shell)", 0, n& - 1, maxscreenx
HandleSort Sorts(), "HeapSort -- (BR Heap)", 0, n& - 1, maxscreenx
HandleSort Sorts(), "CombSort -- Wlodzimierz Dobosiewicz (later, Lacey, Box)", 0, n& - 1, maxscreenx
HandleSort Sorts(), "ShearSort -- some CompuGeeks", 0, 16 * maxscreenx - 1, maxscreenx
ResetScreen% = -1
HandleSort Sorts(), "PostSort -- Your Local Mailman", 0, n& - 1, maxscreenx
BatcherScreenX& = 1
IF BatcherScreenX&
* 2 > maxscreenx
THEN BatcherScreenX& = BatcherScreenX& * 2
BatcherScreenY& = 1
IF BatcherScreenY&
* 2 > maxscreeny
THEN BatcherScreenY& = BatcherScreenY& * 2
xy& = BatcherScreenX& * BatcherScreenY&
HandleSort Sorts(), "Batcher Odd-even MergeSort -- Kenneth E Batcher", 0, xy& - 1, BatcherScreenX&
ResetScreen% = -1
HandleSort Sorts(), "Bucket Sort -- Bucky T (not really)", 0, n& - 1, maxscreenx
HandleSort Sorts(), "MergeSort (recursive)", 0, n& - 1, maxscreenx
HandleSort Sorts(), "QuickSort Recursive (Stable) -- CAR Hoare, Codeguy!", 0, n& - 1, maxscreenx
HandleSort Sorts(), "QuickSort Iterative -- CAR Hoare", 0, n& - 1, maxscreenx
HandleSort Sorts(), "MergeExperiment -- ** codeguy! **", 0, n& - 1, maxscreenx
HandleSort Sorts(), "Bidirectional ShellSort -- guys in white coats & codeguy", 0, n& - 1, maxscreenx
HandleSort Sorts(), "CodeGuySort -- Who Knows but it works -- and fast -- invented by codeguy", 0, n& - 1, maxscreenx
HandleSort Sorts(), "Prime Gap Sort -- codeguy", 0, n& - 1, maxscreenx
HandleSort Sorts(), "QuickStepRecursive", 0, n& - 1, maxscreenx
HandleSort Sorts(), "Tree Sort Ascending -- the keebler elves", 0, 2 * (n& - 1) \ 8, maxscreenx
HandleSort Sorts(), "OESort", 0, n& - 1, maxscreenx
HandleSort Sorts(), "JSort -- Some guy named J", 0, (n& - 1) \ 16, maxscreenx
HandleSort Sorts(), "CodeGuySort -- Who Knows but it works -- and fast -- invented by codeguy", 0, n& - 1, maxscreenx
ResetScreen% = 0
lastsort% = SortNum
nprinted = 0: GetRawSpeed% = -1
IF Sorts
(i
).accumulatedtime
> 0 THEN LOCATE nprinted \
2 + 1, (nprinted
MOD 2) * 40 + 1 PRINT USING "SpeedIndex(lo=fast)####.####:"; SpeedIndex#
(Sorts
(i
), 0, n&
- 1, GetRawSpeed%
, tstart#
, tend#
, maxscreenx
) PRINT USING "Swaps ###,###,###,###,###:"; Sorts
(i
).Swaps
PRINT USING "comparisons#,###,###,###,###:"; Sorts
(i
).compares
PRINT USING "writes #,###,###,###,###:"; Sorts
(i
).writes
PRINT USING "10000(acc)time##,###,###,###:"; Sorts
(i
).accumulatedtime
* 10000 PRINT USING "times executed##,###,###,###:"; Sorts
(i
).runs
PRINT USING "items sorted ###,###,###,###:"; Sorts
(i
).NSorted
PRINT USING "NRetrievals#,###,###,###,###:"; Sorts
(i
).retrievals
PRINT USING "Not Swapped#,###,###,###,###:"; Sorts
(i
).NotSwapped
PRINT USING "Items/sec##,###,###,###.####:"; Sorts
(i
).NSorted
/ Sorts
(i
).accumulatedtime
PRINT USING "time(start) ##,###,###.####:"; Sorts
(i
).timestart
PRINT USING "time(end) ##,###,###.####:"; Sorts
(i
).timeend
nprinted = nprinted + 1
'* PUT #channel%, i, Sorts(i)
'* OpenFile t, "c", channel%, "stats.txt"
SUB OpenFile
(rec
AS SortRec
, mode$
, channel%
, f$
) SUB HandleSort
(s
() AS SortRec
, x$
, start&
, finish&
, maxw
) SortNum = s(SortNum).sorttocall
s
(SortNum
).title
= "[" + LTRIM$(STR$(SortNum
)) + "]" + x$
s(SortNum).sorttocall = SortNum
s(SortNum).NSorted = s(SortNum).NSorted + finish& - start& + 1
FOR i&
= start&
TO finish&
Pixels
(i&
).pcolor
= INT(RND * numcolors%
) + 1 Pixels(i&).pixnum = i&
PixelSet i&, maxw, Pixels(i&).pcolor
s
(SortNum
).timestart
= TIMER QuickSort start&, finish&, maxw
ShellSortMetzler start&, finish&, maxw
FlashSort start&, finish&, maxw
RadixSort start&, finish&, maxw
ShellSort start&, finish&, maxw
ShellSortSinglepass start&, finish&, maxw
HeapSort start&, finish&, maxw
CombSort start&, finish&, maxw
ShearSort start&, finish&, maxw
ResetScreen% = -1
PostSort start&, finish&, maxw
BatcherOddEvenMergeSort start&, finish&, maxw
ResetScreen% = -1
BucketSort start&, finish&, maxw
MergeSort start&, finish&, maxw
QuickSortRStable Pixels(), start&, finish&, maxw
QuickSortIterative start&, finish&, maxw
MergeExperiment start&, finish&, maxw
BidirectionalShellSort start&, finish&, maxw
CodeGuySort start&, finish&, maxw
PrimeGapSort start&, finish&, maxw
QuickStepRecursive start&, finish&, 2, maxw
QuickStepRecursive start&, finish&, 1, maxw
TreeSortAscending start&, finish&, maxw
OESort start&, finish&, maxw
JSort start&, finish&, maxw
CodeGuySort start&, finish&, maxw
s
(SortNum
).timeend
= TIMER s(SortNum).runs = s(SortNum).runs + 1
IF s
(SortNum
).timeend
< s
(SortNum
).timestart
THEN s(SortNum).accumulatedtime = s(SortNum).accumulatedtime + (s(SortNum).timeend - s(SortNum).timestart) + 86400
s(SortNum).accumulatedtime = s(SortNum).accumulatedtime + s(SortNum).timeend - s(SortNum).timestart
SUB SetRandomPixels
(p
() AS PixelRec
, start&
, finish&
, maxw
) FOR i&
= start&
TO finish&
Pixels(i&).pixnum = i&
Pixels
(i&
).pcolor
= INT(RND * numcolors%
) + 1
SUB QuickSort
(start&
, finish&
, maxw
) IF LessThan%
(CompareScreen%
(finish&
, start&
, maxw
)) THEN PixelSwap start&, finish&, maxw
i& = start&
j& = finish&
m%
= GetPixel%
(i&
+ RND * (j&
- i&
+ 1), maxw
) WHILE GetPixel%
(i&
, maxw
) < m%
i& = i& + 1
Sorts(SortNum).compares = Sorts(SortNum).compares + 1
WHILE GetPixel%
(j&
, maxw
) > m%
j& = j& - 1
Sorts(SortNum).compares = Sorts(SortNum).compares + 1
PixelSwap i&, j&, maxw
i& = i& + 1
j& = j& - 1
QuickSort i&, finish&, maxw
QuickSort start&, j&, maxw
'* Radix sort is akin to Postman's sort, however instead of sorting items after they've been inserted into their proper "boxes,"
'* another pass is made using the next character (in this case bit) of the sortation key. bits& can be changed to the number of
'* characters in the sorting key (Field length). RadixSort also has a linear running time, but requires extra storage in exchange
'* for speed. RadixSort is not a true comparison sort. It's actually more of a computed distribution sort than anything else. RadixSort
'* in this implementation is Stable. Speed... Stability... Linear running time... (Hmmm...)
SUB RadixSort
(Start&
, Finish&
, maxw
) 'ChangeTitleBar "RadixSort ****"
FOR i&
= Start&
TO Finish&
t% = GetPixel%(i&, maxw)
h% = t%
DIM PsCount%
(0 TO h%
, Start&
TO Finish&
), ct&
(h%
), Pow2&
(32) bits&
= LOG(h%
+ 2) \
LOG(2) + 1 Pow2&(i) = 2 ^ i
FOR i&
= Start&
TO Finish&
a% = GetPixel%(i&, maxw)
PsCount%(x%, ct&(x%)) = a%
ct&(x%) = ct&(x%) + 1
index& = Start&
FOR i&
= 0 TO ct&
(u%
) - 1 PixelSet index&, maxw, PsCount%(u%, i&)
index& = index& + 1
ct&(u%) = 0
'* this is dl shell's sort but modified for faster running time than standard shellsort.
SUB ShellSortMetzler
(Start&
, Finish&
, maxw
) m& = Metzler&(Start&, Finish&)
FOR j&
= Start&
TO Finish&
- m&
l& = j& + m&
B% = GetPixel%(l&, maxw)
IF GetPixel%
(i&
, maxw
) > B%
THEN PixelSwap i& + m&, i&, maxw
l& = i&
i& = Start&
Sorts(SortNum).compares = Sorts(SortNum).compares + 1
PixelSet l&, maxw, B%
m& = (m& - 1) \ 3
x& = (b& - a& + 1) \ 3
s& = 0
s& = 3 * s& + 1
x& = (x& - 1) \ 3
Metzler& = s&
SUB ShellSort
(start
, finish&
, maxw
) Gap& = (finish& - Start& + 1)
st& = Start&: b& = st&
ends& = finish& - Gap&: a& = ends&
st& = b&
ends& = a&
a& = st&
b& = ends&
IF GetPixel%
(i&
, maxw
) > GetPixel%
(i&
+ Gap&
, maxw
) THEN PixelSwap i&, i& + Gap&, maxw
a& = i&
b& = i&
Gap& = Gap& \ 2
st& = Start&
ends& = finish& - Gap&
SUB ShellSortSinglepass
(start&
, finish&
, maxw
) Gap& = (finish& - start& + 1) \ 1.247#
FOR i&
= start&
TO finish&
- Gap&
IF CompareScreen%
(i&
, i&
+ Gap&
, maxw
) = 1 THEN PixelSwap i&, i& + Gap&, maxw
Gap&
= INT(Gap&
/ 1.247#
)
SUB FlashSort
(Start&
, finish&
, maxw
) m& = .128 * finish&
DIM L
(m&
), a
(Start&
TO finish&
) nmax& = Start&
minptr& = Start&
FOR i&
= Start&
TO finish&
a(i&) = GetPixel%(i&, maxw)
IF CompareScreen%
(i&
, minptr&
, maxw
) = -1 THEN minptr&
= i&
IF CompareScreen%
(i&
, nmax&
, maxw
) = 1 THEN nmax&
= i&
C1# = (m& - 1) / (a(nmax&) - a(minptr&))
L(k&) = 0
FOR i&
= Start&
TO finish&
k&
= 1 + INT(C1#
* (a
(i&
) - a
(minptr&
))) L(k&) = L(k&) + 1
L(k&) = L(k&) + L(k& - 1)
anmin% = a(minptr&)
hold% = a(nmax&)
a(nmax&) = a(Start&)
a(Start&) = hold%
PixelSwap nmax&, Start&, maxw
PixelSet Start&, hold%, maxw
nmove& = 0
j& = 1
k& = m&
WHILE (nmove&
< (finish&
- 1)) j& = j& + 1
k&
= 1 + INT(C1#
* (a
(j&
) - anmin%
)) flash% = a(j&)
PixelSet j&, maxw, flash%
k&
= 1 + INT(C1#
* (flash%
- anmin%
)) PixelSet L(k&), maxw, a(L(k&))
hold% = a(L(k&))
a(L(k&)) = flash%
PixelSet L(k&), maxw, flash%
flash% = hold%
L(k&) = L(k&) - 1
nmove& = nmove& + 1
IF CompareArray%
(a
(), i&
+ 1, i&
) = -1 THEN hold% = a(i&)
j& = i&
WHILE (a
(j&
+ 1) < hold%
) PixelSwap j&, j& + 1, maxw
a(j&) = a(j& + 1)
j& = j& + 1
a(j&) = hold%
PixelSet j&, maxw, hold%
row% = (i& - col%) / maxw
GetPixel%
= POINT(col%
, row%
) Sorts(SortNum).retrievals = Sorts(SortNum).retrievals + 1
SUB PixelSet
(i&
, maxw
, c%
) row% = (i& - col%) / maxw
Sorts(SortNum).writes = Sorts(SortNum).writes + 1
'Pixels(i&).pcolor = c%
SUB PixelSwap
(i&
, j&
, maxw
) a% = GetPixel%(i&, maxw)
b% = GetPixel%(j&, maxw)
Sorts(SortNum).NotSwapped = Sorts(SortNum).NotSwapped + 1
PixelSet j&, maxw, a%
PixelSet i&, maxw, b%
Sorts(SortNum).Swaps = Sorts(SortNum).Swaps + 1
'Pixels(i&).pcolor = b%
'Pixels(j&).pcolor = a%
s% = 0
IF GetPixel%
(i&
, maxw
) > GetPixel%
(j&
, maxw
) THEN s% = 1
IF GetPixel%
(i&
, maxw
) < GetPixel%
(j&
, maxw
) THEN s% = -1
Sorts(SortNum).compares = Sorts(SortNum).compares + 1
CompareScreen% = s%
s% = 0
s% = -1
s% = 1
Sorts(SortNum).compares = Sorts(SortNum).compares + 1
CompareArray% = s%
s% = 0
s% = -1
LessThan% = s%
SUB QuickStepRecursive
(start&
, finish&
, incby%
, maxw
) IF finish&
- start&
< incby%
^ 2 THEN IF LessThan%
(CompareScreen%
(finish&
, start&
, maxw
)) THEN PixelSwap finish&, start&, maxw
ELSE 'IF finish& - start& > incby% ^ 2 THEN i& = start&
remainder%
= (finish&
- start&
) MOD incby%
j& = i& + incby% * ((finish& - start& - remainder%) / incby%)
'j& = start& + incby% * ((finish& - start&) / (incby%))
middle& = i& + (j& - i&) \ (incby%)
m% = GetPixel%(middle&, maxw)
WHILE GetPixel%
(i&
, maxw
) < m%
AND i&
< j&
i& = i& + incby%
WHILE GetPixel%
(j&
, maxw
) > m%
AND j&
> i&
j& = j& - incby%
PixelSwap i&, j&, maxw
i& = i& + incby%
j& = j& - incby%
QuickStepRecursive i&, finish&, incby%, maxw
QuickStepRecursive start&, j&, incby%, maxw
NLOGN#
= n&
* (LOG(n&
) / LOG(2))
' this version of HeapSort can now sort parts of lists, rather than being limited to entire lists. The one that usually appears is one that
' sorts from the beginning to the end.
SUB HeapSort
(Start&
, Finish&
, maxw
) FOR i&
= Start&
+ 1 TO Finish&
PercolateUp Start&, i&, maxw
PixelSwap Start&, i&, maxw
PercolateDown Start&, i& - 1, maxw
SUB PercolateDown
(Start&
, MaxLevel&
, maxw
) i& = Start&
' Move the value in GetPixel%(Start&) down the heap until it has
' reached its proper node (that is, until it is less than its parent
' node or until it has reached MaxLevel&, the bottom of the current heap):
Child& = 2 * (i& - Start&) + Start& ' Get the subscript for the Child& node.
' Reached the bottom of the heap, so exit this procedure:
' If there are two Child nodes, find out which one is bigger:
ax& = Child& + 1
IF CompareScreen%
(ax&
, Child&
, maxw
) = 1 THEN Child& = ax&
' Move the value down if it is still not bigger than either one of
' its Child&ren:
IF CompareScreen%
(i&
, Child&
, maxw
) = -1 THEN PixelSwap i&, Child&, maxw
i& = Child&
' Otherwise, GetPixel%() has been restored to a heap from 0 to MaxLevel&,
' so exit:
SUB PercolateUp
(Start&
, MaxLevel&
, maxw
) i& = MaxLevel&
' Move the value in GetPixel%(MaxLevel&, maxw) up the heap until it has
' reached its proper node (that is, until it is greater than either
' of its Child& nodes, or until it has reached 1, the top of the heap):
Parent& = Start& + (i& - Start&) \ 2 ' Get the subscript for the parent node.
' The value at the current node is still bigger than the value at
' its parent node, so swap these two array elements:
IF CompareScreen%
(i&
, Parent&
, maxw
) = 1 THEN PixelSwap Parent&, i&, maxw
i& = Parent&
' Otherwise, the element has reached its proper place in the heap,
' so exit this procedure:
SUB CombSort
(Start&
, Finish&
, maxw
) ShrinkFactor# = 1.247330950103979#
ShrinkFactor# = 1.3#
gap& = Finish& - Start&
BooleanSwapped% = -1
WHILE (gap&
> 1) OR BooleanSwapped%
gap&
= INT(gap&
/ ShrinkFactor#
) BooleanSwapped% = 0
FOR i&
= Start&
TO Finish&
- gap&
IF CompareScreen%
(i&
, i&
+ gap&
, maxw
) = 1 THEN PixelSwap i&, i& + gap&, maxw
BooleanSwapped% = -1
'* ShearSort rearranges elements into a "square" array and then sorts even and odd sets of columns and rows. this is the slice and dice method of sorting
'* which i assume runs far more quickly on multiprocessors. it is included only as a matter of interest as it is what i consider a "beautiful," even if not
'* blindingly fast sorting method. this is a parallel sorting algo translated to single-processor (could be tackled with simultaneous threading if our man
'* Galleon could find some way to exploit multiple threads and processors).
SUB ShearSort
(start&
, finish&
, maxw
) MakeSquare% = -1
sortorder% = 1
'* put elements into a "square" arrangement.
rows&
= INT(SQR(finish&
- start&
+ 1)) cols& = (finish& - start& + 1) \ rows& + 1
cols& = (finish& - start& + 1) / rows&
rows& = cols&
cols& = rows&
cols& = maxw
rows& = (finish& - start& + 1) / maxw
FOR i&
= start&
TO finish&
PixelSet i&, cols&, Pixels(i&).pcolor
colsminusone& = cols& - 1
rminuslplusoneminuscols& = finish& - start& + 1 - cols&
k& = rows&
'* slice
OETransSort i& + tmpj&, i& + colsminusone&, 1, -sortorder%, cols& '-sortorder%
OETransSort i& + tmpj&, i& + colsminusone&, 1, sortorder%, cols& '+sortorder% +
'* and then dice
FOR i&
= start&
TO start&
+ colsminusone&
OETransSort i&, rminuslplusoneminuscols& + i&, cols&, -sortorder%, cols&
OETransSort i& + tmpj& * cols&, rminuslplusoneminuscols& + i&, cols&, -sortorder%, cols& '-s%
OETransSort i&, i& + colsminusone&, rows&, sortorder%, cols&
OETransSort i& + tmpj&, i& + colsminusone&, rows&, sortorder%, cols&
k&
= (k&
- (k&
MOD 2)) \
2
OETransSort i&, i& + colsminusone&, 1, sortorder%, cols&
OETransSort i& + tmpj&, i& + colsminusone&, 1, sortorder%, cols&
SUB OETransSort
(l&
, r&
, gap&
, order%
, maxw
) rx& = gap&
lst& = r& - rx&
x% = CompareScreen%(i&, i& + gap&, maxw)
PixelSwap i&, i& + gap&, maxw
'* PostSort find the range of the data to be sorted and loads those into "boxes," which is essentially a 2-d array.
'* then sort what's in the "boxes" individually using whatever sort -- in this case quicksort.
SUB PostSort
(start&
, Finish&
, maxw
) FindMinMax start&, Finish&, lptr&, rptr&, maxw
cmin% = GetPixel%(lptr&, maxw)
cmax% = GetPixel%(rptr&, maxw)
DIM PsCount&
(cmin%
TO cmax%
, start&
TO Finish&
), ct&
(cmin%
TO cmax%
) FOR i&
= start&
TO Finish&
x% = GetPixel%(i&, maxw)
PsCount&(x%, ct&(x%)) = x%
ct&(x%) = ct&(x%) + 1
Index& = start&
Last = start&
FOR j&
= 0 TO ct&
(i%
) - 1 PixelSet Index&, maxw, PsCount&(i%, start& + j&)
Index& = Index& + 1
QuickSort Last&, Last& + ct&(i%) - 1, maxw
Last& = Index&
SUB BatcherOddEvenMergeSort
(Start&
, Finish&
, maxw
) m&
= (Finish&
+ (Finish&
MOD 2)) \
2 BatcherOddEvenMergeSort Start&, m&, maxw
BatcherOddEvenMergeSort Start& + m&, m&, maxw
BatcheroddEvenMerge Start&, Finish&, 1, maxw
SUB BatcheroddEvenMerge
(Start&
, Finish&
, r&
, maxw
) m& = r& * 2
BatcheroddEvenMerge Start&, Finish&, m&, maxw
BatcheroddEvenMerge Start& + r&, Finish&, m&, maxw
i& = Start& + r&
IF i&
+ m&
> Start&
+ Finish&
THEN IF GetPixel%
(i&
, maxw
) > GetPixel%
(i&
+ r&
, maxw
) THEN PixelSwap i&, i& + r&, maxw
i& = i& + m&
IF GetPixel%
(Start&
, maxw
) > GetPixel%
(Start&
+ r&
, maxw
) THEN PixelSwap Start&, Start& + r&, maxw
SUB JSortReHeap
(length&
, i&
, maxw
) done% = 0
T% = GetPixel%(i&, maxw)
parent& = i&
child& = 2 * (i& + 1) - 1
IF (child&
< length&
- 1) THEN IF (GetPixel%
(child&
, maxw
) >= GetPixel%
(child&
+ 1, maxw
)) THEN child& = child& + 1
IF (T%
< GetPixel%
(child&
, maxw
)) THEN done% = -1
PixelSet parent&, maxw, GetPixel%(child&, maxw)
parent& = child&
child& = 2 * (parent& + 1) - 1
PixelSet parent&, maxw, T%
SUB JSortInvReHeap
(length&
, i&
, maxw
) done% = 0
T% = GetPixel%(length& - 1 - i&, maxw)
parent& = i&
child& = 2 * (i& + 1) - 1
IF (child&
< length&
- 1) THEN ns& = length& - 1
IF GetPixel%
(ns&
- child&
, maxw
) <= GetPixel%
(ns&
- child&
- 1, maxw
) THEN child& = child& + 1
IF T%
> GetPixel%
(length&
- 1 - child&
, maxw
) THEN done% = -1
PixelSet length& - 1 - parent&, maxw, GetPixel%(length& - 1 - child&, maxw)
parent& = child&
child& = 2 * (parent& + 1) - 1
PixelSet length& - 1 - parent&, maxw, T%
SUB JSort
(start&
, finish&
, maxw
) '// Do an insertion sort on the almost sorted array
FOR j&
= start&
TO finish&
- 1 '// Heapify top down
JSortReHeap i&, j&, maxw
JSortInvReHeap i&, j&, maxw
T% = GetPixel%(j&, maxw)
a& = j&
b& = a&
a& = a& - 1
IF GetPixel%
(a&
, maxw
) > T%
THEN PixelSwap a&, b&, maxw
PixelSet b&, maxw, T%
'* to keep BucketSort stable, you must use a stable sort on Lists&(), or if you prefer speed, just use quicksort if you don't care about
'* sort stability.
SUB BucketSort
(start&
, finish&
, maxw
) FindMinMax start&, finish&, lptr&, rptr&, maxw
min% = GetPixel%(lptr&, maxw)
max% = GetPixel%(rptr&, maxw)
NBuckets&
= SQR(((max%
- min%
) / 2) ^ 2) BucketSize& = 1.28 * (finish& - start& + 1) \ (NBuckets&)
DIM Lists&
(NBuckets&
, BucketSize&
), Counts&
(min%
TO max%
), OverFlowedCt&
(min%
TO max%
) difference& = (max% - min% + 1) \ NBuckets&
FOR i&
= start&
TO finish&
BucketNum& = GetPixel%(i&, maxw) \ difference&
IF Counts&
(BucketNum&
) > BucketSize&
THEN OverFlowedCt&(BucketNum&) = -1
IF Counts&
(BucketNum&
- 1) > BucketSize&
THEN BucketNum& = BucketNum& + 1
BucketNum& = BucketNum& - 1
IF BucketNum&
< NBuckets&
THEN BucketNum& = BucketNum& + 1
Lists&(BucketNum&, Counts&(BucketNum&)) = GetPixel%(i&, maxw)
Counts&(BucketNum&) = Counts&(BucketNum&) + 1
idx& = start&
last& = start&
'* roughly sorts Lists&() in a stable manner
SortBuckets Lists&(), 0, Counts&(i&) - 1, i&, maxw
FOR u&
= 0 TO Counts&
(i&
) - 1 PixelSet idx&, maxw, Lists&(i&, u&)
idx& = idx& + 1
ShellSortMetzler last&, idx& - 1, maxw
last& = idx&
SUB SortBuckets
(Lists&
(), Start&
, Finish&
, ListIndex&
, maxw
) IF Lists&
(ListIndex&
, Start&
) > Lists&
(ListIndex&
, Finish&
) THEN SWAP Lists&
(ListIndex&
, Start&
), Lists&
(ListIndex&
, Finish&
) 'u& = (Finish& - Start&) MOD 2
m& = Start& + (Finish& - Start&) \ 2
SortBuckets Lists&(), Start&, m&, ListIndex&, maxw
SortBuckets Lists&(), m&, Finish&, ListIndex&, maxw
SUB FindMinMax
(start&
, finish&
, MinPtr&
, MaxPtr&
, maxw
) MinPtr& = start&: min% = GetPixel%(start&, maxw)
MaxPtr& = start&: max% = GetPixel%(start&, maxw)
FOR i&
= start&
TO finish&
m% = GetPixel%(i&, maxw)
min% = m%
MinPtr& = i&
max% = m%
MaxPtr& = i&
SUB MergeSort
(start&
, finish&
, maxw
) length& = finish& - start& + 1
middle& = start& + (finish& - start&) \ 2
MergeSort start&, middle&, maxw
MergeSort middle& + 1, finish&, maxw
FOR i&
= 0 TO length&
- 1 temp(i&) = GetPixel%(start& + i&, maxw)
mptr& = 0
sptr& = middle& - start& + 1
FOR i&
= 0 TO length&
- 1 IF sptr&
<= finish&
- start&
THEN IF mptr&
<= middle&
- start&
THEN IF temp
(mptr&
) > temp
(sptr&
) THEN PixelSet i& + start&, maxw, temp(sptr&)
sptr& = sptr& + 1
PixelSet i& + start&, maxw, temp(mptr&)
mptr& = mptr& + 1
PixelSet i& + start&, maxw, temp(sptr&)
sptr& = sptr& + 1
PixelSet i& + start&, maxw, temp(mptr&)
mptr& = mptr& + 1
SUB OESort
(Start&
, Finish&
, maxw
) sorted = 0
sorted = -1
IF CompareScreen%
(i&
, i&
+ 1, maxw
) = 1 THEN PixelSwap i&, i& + 1, maxw
sorted = 0
IF CompareScreen%
(i&
, i&
+ 1, maxw
) = 1 THEN PixelSwap i&, i& + 1, maxw
SUB QuickSortRStable
(r
() AS PixelRec
, start&
, finish&
, maxw
) CompareRecs r(), start&, finish&, maxw
i& = start&
j& = finish&
p# = StableIndex#(r(), (i& + (j& - i& + 1) \ 2), maxw)
WHILE StableIndex#
(r
(), i&
, maxw
) < p#
Sorts(SortNum).compares = Sorts(SortNum).compares + 1
i& = i& + 1
WHILE StableIndex#
(r
(), j&
, maxw
) > p#
Sorts(SortNum).compares = Sorts(SortNum).compares + 1
j& = j& - 1
CompareRecs r(), i&, j&, maxw
i& = i& + 1
j& = j& - 1
QuickSortRStable r(), i&, finish&, maxw
QuickSortRStable r(), start&, j&, maxw
'* swapping indexes is much faster than swapping entire records
'* the index for this Pixels is simply the r().pixnum field of Pixels type PixelRec r()
SUB CompareRecs
(r
() AS PixelRec
, i&
, j&
, maxw
) Sorts(SortNum).compares = Sorts(SortNum).compares + 1
IF r
(r
(i&
).pixnum
).pcolor
<= r
(r
(j&
).pixnum
).pcolor
THEN IF r
(i&
).pixnum
> r
(j&
).pixnum
THEN SWAP r
(i&
).pixnum
, r
(j&
).pixnum
Sorts(SortNum).compares = Sorts(SortNum).compares + 1
IF r
(r
(i&
).pixnum
).pcolor
> r
(r
(j&
).pixnum
).pcolor
THEN SWAP r
(i&
).pixnum
, r
(j&
).pixnum
PixelSet i&, maxw, r(r(i&).pixnum).pcolor
PixelSet j&, maxw, r(r(j&).pixnum).pcolor
IF StableIndex#
(r
(), i&
, maxw
) > StableIndex#
(r
(), j&
, maxw
) THEN PixelSwap r(r(i&).pixnum).pixnum, r(r(j&).pixnum).pixnum, maxw
SWAP r
(i&
).pixnum
, r
(j&
).pixnum
StableIndex# = r(r(a&).pixnum).pcolor * np# + r(a&).pixnum
SUB QuickSortIterative
(Start&
, Finish&
, maxw
) MinStack&
= LOG(Finish&
- Start&
+ 1) \
LOG(2) + 1 DIM LStack&
(MinStack&
, 1) StackPtr% = 0
LStack&(StackPtr%, 0) = Start&
LStack&(StackPtr%, 1) = Finish&
Low& = LStack&(StackPtr%, 0)
Hi& = LStack&(StackPtr%, 1)
i& = Low&
j& = Hi&
Mid& = Low& + (Hi& - Low& + 1) \ 2
Compare% = GetPixel%(Mid&, maxw)
DO WHILE GetPixel%
(i&
, maxw
) < Compare%
Sorts(SortNum).compares = Sorts(SortNum).compares + 1
i& = i& + 1
DO WHILE GetPixel%
(j&
, maxw
) > Compare%
Sorts(SortNum).compares = Sorts(SortNum).compares + 1
j& = j& - 1
PixelSwap i&, j&, maxw
i& = i& + 1
j& = j& - 1
LStack&(StackPtr%, 0) = i&
LStack&(StackPtr%, 1) = Hi&
StackPtr% = StackPtr% + 1
Hi& = j&
LStack&(StackPtr%, 0) = Low&
LStack&(StackPtr%, 1) = j&
StackPtr% = StackPtr% + 1
Low& = i&
StackPtr% = StackPtr% - 1
' this sort splits the list in half and then merges them, however, it requires extra space -- the travails of gaining extra speed!
' but on average, it is quicker than quicksorting the entire list as the arrays are already sorted by the time they get merged, which
' itself is a nearly linear process. as long as a stable sort is used to sort array segments, this should remain a stable sort!
SUB MergeExperiment
(Start&
, Finish&
, maxw
) HowManySets = 2 'LOG(Finish& - Start& + 1) \ LOG(2) + 1
DIM Starts&
(HowManySets
), Ends&
(HowManySets
) m&
= (Finish&
- Start&
) MOD HowManySets
segment& = (Finish& - Start& - m&) / HowManySets
u = HowManySets - 1
f& = Finish&
Ends&(u) = f&
Starts&(u) = f& - segment&
f& = f& - (segment& + 1)
u = u - 1
index& = 0
FOR i
= 0 TO HowManySets
- 1 MergeSort Starts&(i), Ends&(i), maxw
mergetosum& = 0
StartMast& = Starts&(i)
EndMast& = Ends&(i)
StartSlave& = Starts&(i + 1)
EndSlave& = Ends&(i + 1)
REDIM Master%
(StartMast&
TO EndMast&
) REDIM Slave%
(StartSlave&
TO EndSlave&
) FOR i&
= StartMast&
TO EndMast&
Master%(i&) = GetPixel%(i&, maxw)
FOR i&
= StartSlave&
TO EndSlave&
Slave%(i&) = GetPixel%(i&, maxw)
Master& = StartMast&
Slave& = StartSlave&
index& = Start&
IF Slave&
> EndSlave&
THEN '* both lists are fully traversed ELSE '* empty the slave list PixelSet index&, maxw, Slave%(Slave&)
Slave& = Slave& + 1
IF Slave&
> EndSlave&
THEN '* empty the master list PixelSet index&, maxw, Master%(Master&)
Master& = Master& + 1
ELSE '* Master%() and Slave%() both have unprocessed elements IF Master%
(Master&
) > Slave%
(Slave&
) THEN PixelSet index&, maxw, Slave%(Slave&)
Slave& = Slave& + 1
PixelSet index&, maxw, Master%(Master&)
Master& = Master& + 1
index& = index& + 1
'* part 2, dammit!
'* this has been modified to become a bidirectional shellsort, which is far faster than the bubblesort version, which is a special case where
'* gap& is 1, and runs in polynomial time when gap& is 1
SUB BidirectionalShellSort
(Start&
, Finish&
, maxw
) gap& = (Finish& - Start& + 1) \ 2
up% = -1: down% = -1
startup& = Start&: endup& = Finish& - gap&: FirstUp& = Finish& - gap&: LastUp& = Start&
startdn& = Finish&: enddown& = Start& + gap&: FirstDown& = Start& + gap&: LastDown& = Finish&
up% = 0
FOR i&
= startup&
TO endup&
IF CompareScreen%
(i&
, i&
+ gap&
, maxw
) = 1 THEN PixelSwap i&, i& + gap&, maxw
FirstUp& = i&
LastUp& = i&
up% = -1
startup& = FirstUp&
endup& = LastUp&
'*******************************
down% = 0
IF CompareScreen%
(i&
, i&
- gap&
, maxw
) = -1 THEN PixelSwap i&, i& - gap&, maxw
FirstDown& = i&
LastDown& = i&
down% = -1
startdn& = FirstDown&
enddown& = LastDown&
SWAP FirstDown&
, LastDown&
gap& = gap& \ 2
'* for highly repetitive data, TreeSortAscending becomes like an insertion sort, which degenerates to polynomial time, which is NOT good. this sort is far
'* better suited to data that is not repetitive. by the way, 16 is an arbitrary number and can be set to whatever your threshold of pain for a possibly
'* polynomial time sort.
SUB TreeSortAscending
(start&
, finish&
, maxw
) FindMinMax start&, finish&, MinPtr&, MaxPtr&, maxw
delta# = GetPixel%(MaxPtr&, maxw) - GetPixel%(MinPtr&, maxw)
IF delta#
= 0 THEN 'already sorted because they're all equal IF ABS((finish&
- start&
+ 1) / delta#
) > 65535 THEN BucketSort start&, finish&, maxw
NilValue% = GetPixel%(MinPtr&, maxw) - 1
DIM tree
(start&
+ 1 TO finish&
+ 1) AS TreeNode
FOR x&
= start&
+ 1 TO finish&
+ 1 tree(x&).value = NilValue%
tree(x&).left = NilValue%
tree(x&).right = NilValue%
tree(1).value = GetPixel%(1 - 1, maxw)
free& = 2
pointer& = 1
xv& = (GetPixel%(x& - 1, maxw))
IF xv&
< tree
(pointer&
).value
THEN IF tree
(pointer&
).left
= NilValue%
THEN tree(pointer&).left = free&
tree(free&).value = xv&
'PixelSet free& - 1, maxw, tree(tree(pointer&).left).value
free& = free& + 1
pointer& = tree(pointer&).left
IF tree
(pointer&
).right
= NilValue%
THEN tree(pointer&).right = free&
tree(free&).value = xv&
'PixelSet free& - 1, maxw, tree(tree(pointer&).right).value
free& = free& + 1
pointer& = tree(pointer&).right
depth& = 1
traverse start& + 1, depth&, tree(), NilValue%, maxw
SUB traverse
(start&
, depth&
, tree
() AS TreeNode
, NilValue%
, maxw
) IF tree
(start&
).left
<> NilValue%
THEN traverse tree
(start&
).left
, depth&
, tree
(), NilValue%
, maxw
PixelSet depth& - 1, maxw, tree(start&).value
depth& = depth& + 1
IF tree
(start&
).right
<> NilValue%
THEN traverse tree
(start&
).right
, depth&
, tree
(), NilValue%
, maxw
'* this algo at first glance looks like it'd be just another slow version of shellsort, but crap if it doesn't rank well with my sortindex at 31
SUB CodeGuySort
(Start&
, Finish&
, maxw
) 'rows& = (Finish& - Start& + 1) / maxw
gap& = (Finish& - Start& + 1) \ 2
m& = Start&
FOR x%
= 0 TO (Finish&
- Start&
+ 1) \ maxw
ShellSortMetzler m&, m& + gap&, maxw
m& = m& + gap&
rows& = (Finish& - Start& - gap&) / maxw
FOR x%
= b%
TO (maxw
- gap&
) \ gap&
STEP b%
+ 1 y& = j& * maxw + offset&
z& = y& + gap&
exitnextfor = -1
IF CompareScreen%
(y&
, z&
, maxw
) = 1 THEN PixelSwap y&, z&, maxw
exitnextfor = 0
gap&
= INT((gap&
/ 5) * 4)
SUB SortColumns
(Start&
, Finish&
, maxw
) FOR column&
= 0 TO maxw
- 1 IF GetPixel%
(column&
, maxw
) > GetPixel%
(column&
+ maxw
, maxw
) THEN PixelSwap column&, column& + maxw, maxw
'* uses PrimeNumber&() function to calculate the prime number less than or equal to the gap
SUB PrimeGapSort
(start&
, finish&
, maxw
) Gap& = (finish& - start& + 1)
FOR i&
= start&
TO finish&
- Gap&
'IF i& > finish& - Gap& THEN
' IF CompareScreen%(i&, i& + Gap& - finish&, maxw) = -1 THEN
' PixelSwap i&, i& + Gap& - finish&, maxw
' END IF
'ELSE
IF CompareScreen%
(i&
, i&
+ Gap&
, maxw
) = 1 THEN PixelSwap i&, i& + Gap&, maxw
'END IF
'IF i& < Gap& THEN
' IF CompareScreen%(i&, i& - Gap& + finish&, maxw) = 1 THEN
' PixelSwap i&, i& - Gap& + finish&, maxw
' END IF
'ELSE
' IF CompareScreen%(i&, i& - Gap&, maxw) = -1 THEN
' PixelSwap i&, i& - Gap&, maxw
' END IF
'END IF
Gap& = primeNumber&(Gap& * .727)
'PrimeNumber&(Gap& \ 2)
IF CompareScreen%
(i&
+ 1, i&
, maxw
) = -1 THEN hold% = GetPixel%(i&, maxw)
j& = i&
WHILE (GetPixel%
(j&
+ 1, maxw
) < hold%
) PixelSwap j&, j& + 1, maxw
'a(j&) = a(j& + 1)
j& = j& + 1
'a(j&) = hold%
PixelSet j&, maxw, hold%
' Find a prime number below a& (excluding 3 and 5)
'
' Notice that there is a:
' 59,9% chance for a single successive guess,
' 83,9% chance for a successive guess out of two guesses,
' 93,6% chance for a successive guess out of three guesses,
' 97,4% chance for a successive guess out of four guesses,
' 99,98% chance for a successive guess out of ten guesses...
'
' Worst bad luck over 10000 tested primes: 19 guesses.
STATIC pps%
() 'Previous Prime in Sequence. Contains about 59.9% of all primes modulo 30.
firstCall% = -1
' Map numbers from 0 to 29 to the next lower prime in the sequence {1,7,11,13,17,19,23,29}.
pps%(0) = -1: pps%(1) = -1 ' -1 = 29 (modulo 30)
pps%(2) = 1: pps%(3) = 1: pps%(4) = 1: pps%(5) = 1: pps%(6) = 1: pps%(7) = 1
pps%(8) = 7: pps%(9) = 7: pps%(10) = 7: pps%(11) = 7
pps%(12) = 11: pps%(13) = 11:
pps%(14) = 13: pps%(15) = 13: pps%(16) = 13: pps%(17) = 13
pps%(18) = 17: pps%(19) = 17
pps%(20) = 19: pps%(21) = 19: pps%(22) = 19: pps%(23) = 19
pps%(24) = 23: pps%(25) = 23: pps%(26) = 23: pps%(27) = 23: pps%(28) = 23: pps%(29) = 23
b& = a& + 1
c& = (b& \ 30) * 30: b& = c& + pps%(b& - c&)
div& = 3
div& = div& + 2
c& = (b& \ 30) * 30: b& = c& + pps%(b& - c&)
div& = 3
primeNumber& = b&
FUNCTION SpeedIndex#
(T
AS SortRec
, start&
, finish&
, doit%
, tstart#
, tend#
, maxw
) FOR npixel&
= start&
TO finish&
p% = GetPixel%(npixel&, maxw)
tend# = tend# + 86400
doit% = 0
SpeedIndex# = ((finish& - start& + 1) / (tend# - tstart#)) / (T.NSorted / T.accumulatedtime)