home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / QBAS / BAS_SORT.ZIP / SPLITSRT.BAS < prev   
BASIC Source File  |  1987-10-06  |  10KB  |  243 lines

  1. REM ----- "SPLITSRT"
  2.  
  3. ' By J. G. Krol  Copyright 1987 Sep 29
  4. ' Duplication for personal use allowed, but not for commercial use
  5.  
  6. ' TO USE SPLITSORT AS A QUICKBASIC 3.0 SUBPROGRAM,
  7. ' DIMENSION TWO NUMERICAL DATA ARRAYS:
  8. ' N = ARRAY SIZE FROM 0 BASE (N+1 DATA, TOTAL)
  9. ' XRAW(N) = RAW DATA FROM CALLING PROGRAM
  10. ' XSORTED(N) = SORTED DATA BACK TO CALLING PROGRAM
  11. ' THEN CALL THE SUBPROGRAM WITH:
  12. ' CALL SPLITSORT(XRAW(), XSORTED(), N)
  13.  
  14. ' SAMPLE DRIVER
  15.     N = 20
  16.     DIM XRAW(N), XSORTED(N)
  17.     FOR L = 0 TO N
  18.         XRAW(L) = 20 - L
  19.     NEXT L
  20.     CALL SPLITSORT(XRAW(), XSORTED(), N)
  21.     PRINT
  22.     PRINT"(SPACE) to show results"
  23.     WHILE INKEY$ <> CHR$(32):WEND
  24.     PRINT
  25.     PRINT" SHOW L, XRAW(L), AND XSORTED(L)"
  26.     PRINT
  27.     FOR L = 0 TO N
  28.         PRINT L, XRAW(L), XSORTED(L)
  29.     NEXT L
  30.     END
  31.  
  32.  
  33. SUB SPLITSORT (RAW(1), SORTED(1), N) STATIC
  34. PRINT
  35. PRINT"Sorting"
  36. ' MOVE RAW DATA INTO OUTPUT ARRAY
  37.     FOR L = 0 TO N
  38.         SORTED(L) = RAW(L)
  39.     NEXT L
  40. ' DIMENSION WITH A VARIABLE TO FORCE THE ARRAYS TO BE DYNAMIC
  41. ' SO THAT THEY CAN BE DISARRAYED WITH AN "ERASE"
  42. ' SO THAT THEY CAN BE REDIMENSIONED THE NEXT TIME THROUGH
  43.     STACKSIZE = 20
  44.     DIM LOWEND(STACKSIZE), HIGHEND(STACKSIZE)
  45. ' INITIALIZE THE PROBLEM POINTER STACK
  46.     STACKPOINTER = 1
  47.     MAXSTACKPOINTER = 1' FOR REFERENCE
  48.     LOWEND(1) = 0
  49.     HIGHEND(1) = N
  50.     ' MAIN PROBLEM LOOP - DO ANY AVAILABLE SORTING PROBLEM
  51.     DO UNTIL STACKPOINTER = 0
  52.         ' CROSSED LIMITS MEAN NULL PROBLEM
  53.         DO WHILE HIGHEND(STACKPOINTER) > LOWEND(STACKPOINTER)
  54.             LOW = LOWEND(STACKPOINTER)
  55.             HIGH = HIGHEND(STACKPOINTER)
  56.             GAP = LOW + INT((HIGH - LOW)/2)
  57.             PIVOT = SORTED(GAP)
  58.             WHILE HIGH > LOW
  59.                 ' SCAN UPWARDS TOWARDS THE GAP FOR A BIG VALUE
  60.                 IF LOW < GAP THEN
  61.                     FOR SCAN = LOW TO GAP
  62.                         IF SORTED(SCAN) > PIVOT THEN
  63.                             SORTED(GAP) = SORTED(SCAN)' FILL THE OLD GAP
  64.                             GAP = SCAN' LOCATE THE NEW GAP
  65.                             EXIT FOR' A NEW COMMAND IN QB 3.0
  66.                         END IF
  67.                     NEXT SCAN
  68.                     LOW = GAP
  69.                 END IF
  70.                 ' SCAN DOWNWARDS TOWARDS THE GAP FOR A SMALL VALUE
  71.                 IF HIGH > GAP THEN
  72.                     FOR SCAN = HIGH TO GAP STEP -1
  73.                         IF SORTED(SCAN) < PIVOT THEN
  74.                             SORTED(GAP) = SORTED(SCAN)' FILL THE OLD GAP
  75.                             GAP = SCAN' LOCATE THE NEW GAP
  76.                             EXIT FOR
  77.                         END IF
  78.                     NEXT SCAN
  79.                     HIGH = GAP
  80.                 END IF
  81.             WEND
  82.             ' FILL THE FINAL GAP
  83.             SORTED(GAP) = PIVOT
  84.             ' THE FILE IS NOW PARTITIONED AT THE FINAL GAP LOCATION
  85.             ' STACK UP THE TWO NEW PROBLEMS
  86.             LOWENDLENGTH = GAP - LOWEND(STACKPOINTER)
  87.             HIGHENDLENGTH = HIGHEND(STACKPOINTER) - GAP
  88.             ' PUT LONGER PROBLEM ON STACK FIRST
  89.             ' OVERWRITING THE PROBLEM JUST SOLVED
  90.             IF LOWENDLENGTH < HIGHENDLENGTH THEN
  91.                 LOWEND(STACKPOINTER+1) = LOWEND(STACKPOINTER)
  92.                 HIGHEND(STACKPOINTER) = HIGHEND(STACKPOINTER)
  93.                 LOWEND(STACKPOINTER) = GAP + 1
  94.                 HIGHEND(STACKPOINTER+1) = GAP - 1
  95.             ELSE
  96.                 LOWEND(STACKPOINTER) = LOWEND(STACKPOINTER)
  97.                 HIGHEND(STACKPOINTER+1) = HIGHEND(STACKPOINTER)
  98.                 LOWEND(STACKPOINTER+1) = GAP + 1
  99.                 HIGHEND(STACKPOINTER) = GAP -1
  100.             END IF
  101.             STACKPOINTER = STACKPOINTER + 1
  102.             IF STACKPOINTER > MAXSTACKPOINTER THEN_
  103.                 MAXSTACKPOINTER = STACKPOINTER
  104.         LOOP
  105.         STACKPOINTER = STACKPOINTER - 1
  106.     LOOP
  107. ERASE LOWEND, HIGHEND
  108. PRINT
  109. PRINT"Data are now sorted"
  110. PRINT"Maximum stackpointer was";MAXSTACKPOINTER
  111. END SUB
  112.  
  113. ' Program description:
  114.  
  115. ' SPLITSORT is a "partition" sorting algorithim with two advantages
  116. ' over the classical QUICKSORT algorithim that has long been the
  117. ' standard of comparison.
  118.  
  119. ' Partition sorts repeatedly divide the given array into three parts:
  120. ' 1. The "lower part" up to the "pivot"; all numbers in the lower part
  121. '    are constructed to be no bigger than the pivot itself. Given M
  122. '    numbers to sort, the lower part may contain 0 to M-1 numbers.
  123. ' 2. The pivot, a single number.
  124. ' 3. The "upper part" from the pivot to the end; all numbers in the
  125. '    upper part of the array are constructed to be no smaller than
  126. '    the pivot.  The upper part may contain 0 to M-1 numbers.
  127.  
  128. ' The result of such a partition is to change the given problem of
  129. ' sorting M numbers into three subproblems, each independent of the
  130. ' other two:
  131. ' 1. Sort the lower part.  If the lower part contains but 1 or 0 numbers,
  132. '    then this becomes a null problem: nothing needs to be done.
  133. ' 2. Sort the pivot, a single number.  This is obviously a null problem.
  134. ' 3. Sort the upper part.  If it contains but 1 or 0 numbers, again
  135. '    there's really nothing to do.
  136.  
  137. ' Repeatedly partitioning the original array reduces the original,
  138. ' dificult, time-consuming sorting problem into a number of null
  139. ' problems.  Thus a partition sort sorts by avoiding all sorting.
  140.  
  141. ' In the best case, the pivot ends up in the middle of a given array. Then
  142. ' the lower and upper parts each contain about M/2 numbers.  Each of the
  143. ' two new subproblems is (a bit less than) half as long as the old
  144. ' problem. In this ideal case, the number of comparisions and thus the
  145. ' time required to sort a given array vary in proportion to M*log(M).
  146. ' Since log(M) increases very slowly compared to M itself, the sorting
  147. ' time increases only modestly faster than the number of numbers to be
  148. ' sorted.
  149.  
  150. ' In the worst case, however, the pivot winds up in the first (last)
  151. ' position, the lower (upper) part contains 0 items, the upper (lower)
  152. ' part contains M-1 items, and the resulting sorting time varies as
  153. ' M*M.  Since M-squared increases much faster than M itself, the time
  154. ' soon becomes prohibitively long as M increases.  Thus the BUBBLE SORT,
  155. ' SELECT SORT, and INSERT SORT -- all of which vary as M*M -- are fine
  156. ' for short arrays, but impracticable for long arrays.
  157.  
  158. ' The time taken by any partition sort varies between the
  159. ' best case and the worst case, depending upon the particular array
  160. ' being sorted.  In a theoretical sense, averaging sorting time over
  161. ' all possible data configurations, each considered equally likely
  162. ' to exist, QUICKSORT and SPLITSORT both vary as M*log(M).
  163.  
  164. ' The peculiar and potentially disasterous quirk of QUICKSORT is that
  165. ' its worst case array configuration -- the cases in which its time
  166. ' actually varies as M*M instead of the theoretical M*log(M) -- is a
  167. ' sorted or antisorted array.  Nearly-sorted and nearly-antisorted arrays
  168. ' are nearly as bad. Since such configurations are highly likely to exist
  169. ' in a real data processing setting, QUICKSORT can be very trecherous.
  170.  
  171. ' Here is what can happen.  You sort a random array in a couple of minutes,
  172. ' per the M*log(M) timing.  You now change a few values in the array, and
  173. ' try to resort it.  Intuitively, this ought to take even less time, since
  174. ' most of the numbers already are sorted.  Not so. QUICKSORT may now run
  175. ' for hours before it's done, since its performance is now near the worst-
  176. ' case timing of M*M!
  177.  
  178. ' This infamously trecherous behavior has been attacked various ways:
  179.  
  180. ' 1. Provide whatever manual and programmed means are necessary to
  181. '    avoid apply QUICKSORT to ill-conditioned arrays.  This of course
  182. '    requires some other sorting algorithm to handle those cases.  The
  183. '    nearly sorted condition that makes QUICKSORT work worst happily
  184. '    makes BUBBLE SORT and INSERT SORT work best (very nearly proportional
  185. '    to M).
  186.  
  187. ' 2. Deliberately unsort every array before attempting to sort it.  This
  188. '    requires some randomizing routine to scramble the numbers, and is
  189. '    a paradoxical approach, to say the least.
  190.  
  191. ' 3. Devise some more-or-less elaborate scheme for choosing the pivot.
  192. '    The original QUICKSORT took the first number in the array as the
  193. '    pivot.  If the numbers are "randomly" ordered, the expected value
  194. '    of each number is the average of all the numbers, so the expected
  195. '    final location of the pivot (at which the array will be partitioned)
  196. '    is virtually in the middle (the ideal condition).  Thus there is no
  197. '    advantage to any other choice of a pivot: one record is as good
  198. '    as another, on average.  To get a better choice, you can examine
  199. '    the first several numbers (maybe 3 or 5 of them), doing a little
  200. '    subsort to find the middle one, and use it as the pivot.
  201.  
  202. ' Clearly, all those options are clumsy and troublesome.  But they're
  203. ' the sort of things you have to do to apply QUICKSORT to real-world
  204. ' sorting problems.
  205.  
  206. ' SPLITSORT works *consisently best* for arrays that are actually sorted
  207. ' or nearly sorted or random or reverse-sorted or nearly reverse-sorted,
  208. ' that is, for all data configurations most likely to be encountered.
  209. ' As with any possible partition sort, it does have a worst case
  210. ' in which its time goes as M*M, not M*log(M).  But this is a queer
  211. ' sequence of values extremely unlikely to exist in practice. SPLITSORT
  212. ' is thus a much more robust, reliable, versatile and dependable algorithm
  213. ' than the classical QUICKSORT.  You can apply it indiscriminately.  There's
  214. ' no need for the sort of special tricks described above.
  215.  
  216. ' Nor is there any speed penalty for this greater consistency and
  217. ' dependability. There's actually a slight speed *increase*. Here's why.
  218.  
  219. ' SPLITSORT stores the pivot at the start of each problem, creating
  220. ' a logical gap in the array.  Then it fills that gap with a selected
  221. ' number from the array, creating a new gap at that number's old
  222. ' location, which new gap it then fills with the next-selected
  223. ' number, etc. until a final gap location is attained.  The pivot
  224. ' is then put back into that gap. Thus SPLITSORT takes N+1 assignments
  225. ' to move N numbers.
  226.  
  227. ' QUICKSORT, like all classical sorts, needs 3 assignments to move
  228. ' 2 numbers, e.g., TEMP = X, X = Y, Y = TEMP.  This takes 3N/2
  229. ' assignments to move N numbers, or about 50% more assignments and
  230. ' thus 50% more time than SPLITSORT. In terms of the time spent moving
  231. ' numbers, SPLITSORT is always slightly faster than QUICKSORT -- a nice
  232. ' though noncritical advantage.
  233.  
  234. ' The critical advantage is in terms of the time spent comparing numbers,
  235. ' and the way that time varies as a function of the particular ordering of
  236. ' numbers in a given data array. From this viewpoint, SPLITSORT is at least
  237. ' as fast as QUICKSORT when QS works best (random data) and is decisively
  238. ' faster than QS in the several important and frequent situations where QS
  239. ' misbehaves.
  240.  
  241. ' SPLITSORT is consistently fast and dependable.
  242.  
  243.