home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume34 / flogger / part01 < prev    next >
Encoding:
Text File  |  1992-12-17  |  52.9 KB  |  1,790 lines

  1. Newsgroups: comp.sources.misc
  2. From: mikey@ontek.com (Mike Lee)
  3. Subject:  v34i073:  flogger - Sort Flogger v0.0, Part01/02
  4. Message-ID: <csm-v34i073=flogger.091818@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: ff0ada04ad7449b6a5af60991e3ce2a2
  6. Date: Fri, 18 Dec 1992 15:21:46 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: mikey@ontek.com (Mike Lee)
  10. Posting-number: Volume 34, Issue 73
  11. Archive-name: flogger/part01
  12. Environment: UNIX
  13.  
  14. This is a small collection of some of the more popular sort
  15. algorithms, including:
  16.  
  17.       bubble sort -- any 1st semester course in CS
  18.       heap sort -- contributed by der Mouse
  19.       insertion sort -- any 1st semester course in CS
  20.       merge sort -- roughly patterned after Knuth Vol. 3
  21.       quick sort -- C.A.R. Hoare's as given in K&R 2 pg 87
  22.       shell sort -- D.L. Shell as given in K&R 2 pg 62
  23.       bogo sort -- worst-case sort by Richard Krehbiel
  24.  
  25. A slightly weird test routine is provided which calculates some
  26. performance measurements on the above algorithms and also on the
  27. qsort() function provided with your system, as well as verifying that
  28. the sort actually worked and that it didn't modify anything immediately
  29. above or below the array, that it doesn't leak memory, and whether
  30. or not it's stable.  These tests are carried out in a variety of
  31. situations designed to highlight worst-case behavior.
  32.  
  33. These implementations of the sort functions are all compatible with
  34. qsort()'s parameter list, so if you think your application spends too
  35. much time sorting, you can just s/qsort/merge_sort/ and link in the
  36. sort library and give it a try.  If you think it doesn't spend *enough*
  37. time sorting, try bubble_sort instead.
  38.  
  39. The heapsort was contributed by mouse@larry.mcrcim.mcgill.edu
  40. aka "der Mouse".
  41. ------
  42. #! /bin/sh
  43. # This is a shell archive.  Remove anything before this line, then feed it
  44. # into a shell via "sh file" or similar.  To overwrite existing files,
  45. # type "sh file -c".
  46. # Contents:  README OPTIMIZING TODO flogger.c heap_sort.c merge_sort.c
  47. #   quick_sort.c
  48. # Wrapped by kent@sparky on Thu Dec 17 13:50:34 1992
  49. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  50. echo If this archive is complete, you will see the following message:
  51. echo '          "shar: End of archive 1 (of 2)."'
  52. if test -f 'README' -a "${1}" != "-c" ; then 
  53.   echo shar: Will not clobber existing file \"'README'\"
  54. else
  55.   echo shar: Extracting \"'README'\" \(7993 characters\)
  56.   sed "s/^X//" >'README' <<'END_OF_FILE'
  57. X
  58. XVERSION
  59. X
  60. X    This is version 0 of the the Sort Flogger.
  61. X
  62. XOVERVIEW
  63. X
  64. X    This is a small collection of some of the more popular sort
  65. Xalgorithms, including:
  66. X
  67. X      bubble sort -- any 1st semester course in CS
  68. X      heap sort -- contributed by der Mouse
  69. X      insertion sort -- any 1st semester course in CS
  70. X      merge sort -- roughly patterned after Knuth Vol. 3
  71. X      quick sort -- C.A.R. Hoare's as given in K&R 2 pg 87
  72. X      shell sort -- D.L. Shell as given in K&R 2 pg 62
  73. X      bogo sort -- worst-case sort by Richard Krehbiel
  74. X
  75. X    A slightly weird test routine is provided which calculates some
  76. Xperformance measurements on the above algorithms and also on the
  77. Xqsort() function provided with your system, as well as verifying that
  78. Xthe sort actually worked and that it didn't modify anything immediately
  79. Xabove or below the array, that it doesn't leak memory, and whether
  80. Xor not it's stable.  These tests are carried out in a variety of
  81. Xsituations designed to highlight worst-case behavior.
  82. X
  83. X    These implementations of the sort functions are all compatible with
  84. Xqsort()'s parameter list, so if you think your application spends too
  85. Xmuch time sorting, you can just s/qsort/merge_sort/ and link in the
  86. Xsort library and give it a try.  If you think it doesn't spend *enough*
  87. Xtime sorting, try bubble_sort instead.
  88. X
  89. X    The merge sort declares a global int called _maybe_sorted which
  90. Xtells merge sort that the data in the array may already be mostly in
  91. Xorder.  It is advisory--the algorithm will produce the correct results
  92. Xregardless of _maybe_sorted's value; however the execution time for
  93. Xmerge_sort will be quite a bit less if this is set and the array is
  94. Xalready mostly sorted.  If the array isn't sorted at all, this option
  95. Xextracts about 2% speed penalty.
  96. X
  97. X    The heapsort was contributed by mouse@larry.mcrcim.mcgill.edu
  98. Xaka "der Mouse".
  99. X
  100. X    The merge_sort() function is the only one I've taken any trouble to
  101. Xoptimize.
  102. X
  103. XINSTALLATION
  104. X
  105. X    See the INSTALLATION document which should be nearby.
  106. X
  107. XUSAGE
  108. X
  109. X    Just type "flogger" or "flogger <number>" and watch what happens.
  110. X
  111. XDESCRIPTION OF OUTPUT
  112. X
  113. X    It seems like it doesn't really do anything but spit out numbers,
  114. Xand rather slowly at that.  The version and patch level of the program
  115. Xis printed; the resolution of the clock is printed; the size of the
  116. Xelements is reported; and the number of elements to be sorted is
  117. Xreported.
  118. X
  119. X    For each sort algorithm, a table of measurements is reported.  The
  120. Xrows describe the situation the sort algorithm was presented with for
  121. Xthose measurements and the columns represent the type of measurement
  122. Xtaken.  The rows (situations) are:
  123. X
  124. X    random:   The contents of the array to be sorted are pseudo 
  125. X              random numbers generated by rand(), with two special
  126. X              values excluded for the purpose of detecting overwrites
  127. X              at the ends of the array.
  128. X    ascend:   The array is already completely in order.  To simply
  129. X              verify this fact is all that's required of the sort
  130. X              algorithm; ironically, bubble sort outperforms all
  131. X              the rest in this case.
  132. X    descend:  The array is exactly in reverse order.  Theoretically,
  133. X              an sort function could detect this and swap ends in
  134. X              linear time, but it hardly seems useful.
  135. X    fib asc:  The contents of the array are irrelevant; the comparison
  136. X              function passed to the routine always says that its
  137. X              first argument is less than its second.
  138. X    fib desc: Similarly, the comparison function always says that its
  139. X              first argument is greater than its second.
  140. X    surprise: A pseudorandom result is returned from the comparison 
  141. X              function in an attempt to confound the algorithms' efforts
  142. X              at sorting.
  143. X    mostly:   Similar to ascend, but the first and last elements
  144. X              are reversed.  This is meant to simulate an index which
  145. X              is pretty much already sorted and only a small number
  146. X              of new items need to be inserted.
  147. X    equiv:    The comparison function reports that all elements 
  148. X              compare equal.  The data is arranged so that a
  149. X              check can be made for whether the algorithm is
  150. X              stable; that is the property that records with
  151. X              equal keys stay in the same relative order in the
  152. X              array that they were in before the sort began.
  153. X
  154. XThe columns refer to these measurements:
  155. X
  156. X    compares: The number of calls to the comparison routine during
  157. X              the sort.  I consider this very important, as most
  158. X              of the sorting bottlenecks I've experience center
  159. X              around the comparison function.
  160. X    stack:    (Estimated) Some semi-non-portable attempts to record
  161. X              the growth of the stack are made and a number comes
  162. X              out.  I consider O(log n) use of the stack acceptable
  163. X              on modern machines and none of these algorithms are
  164. X              worse than that. 
  165. X    heap:     Amount of malloc'd storage as reported by mallinfo().
  166. X              If your C library doesn't support mallinfo(), the
  167. X              compiler will probably barf on flogger.c.  The flogger
  168. X              checks for memory leaks.
  169. X    user:     Amount of user mode CPU time as reported by times().
  170. X              This includes time for both the operation of the
  171. X              sort function and the comparison function; as these
  172. X              are only marginally related, this number is not
  173. X              useful for estimating how long it might take to 
  174. X              sort useful data in some other program.
  175. X    system:   Amount of system CPU time as reported by times().
  176. X              Generally 0.00 or very small.  If a sort algorithm
  177. X              uses lots of system time it's probably a Trojan horse
  178. X              trying to break into the passwd file or delete your
  179. X              home directory or something so maybe you should
  180. X              start shuffling through your desk looking for a recent
  181. X              backup tape.  I may remove this in a future version
  182. X              (the report of system time, not the Trojan horse)
  183. X              in favor of another metric, perhaps wall clock time.
  184. X
  185. X    But it isn't enough simply to be fast, a sort algorithm also has
  186. Xto be correct.  To that end, the flogger routine verifies that
  187. Xthe array was actually sorted, at least when the comparison routine
  188. Xwasn't lying.  It also checks that magic values in the memory locations
  189. Ximmediately above and below the array were not accidentally accessed
  190. Xor overwritten.
  191. X
  192. X    The bogo sort run is skipped if n is sufficiently large that
  193. Xit's execution would run into trillions of cycles (approx n = 15).
  194. X
  195. XMISCELLANEOUS
  196. X
  197. X    When running the test routine, some sorts take so long that you
  198. Xmight lose patience.  Keyboard interrupt (aka Control-C) will abort the
  199. Xcurrent sort test and move on to the next.  If you really want the
  200. Xprogram to end, give it a quit signal (Control-\) or send it a signal
  201. Xwith the kill command.   You can also background it (Control-Z) from
  202. Xthe C-shell then kill it.
  203. X
  204. X    The size of the elements being sorted is hard-coded at the moment,
  205. Xbut it can be changed by going into flogger.c and changing the typedefs for
  206. X
  207. X    #define TEST_TYPE double
  208. X    #define TEST_FUNC double_compare
  209. X
  210. Xinto
  211. X
  212. X    #define TEST_TYPE int
  213. X    #define TEST_FUNC int_compare
  214. X
  215. Xor back again.  Or add a new type and a new comparison function.
  216. X
  217. X    Several of the sort algorithms are not re-entrant which means
  218. Xyou shouldn't call the sort from within the very same comparison 
  219. Xfunction you passed into that sort in the first place.
  220. X
  221. XCOPYRIGHT
  222. X
  223. X    Since none of the sort algorithms are mine and anyone with a copy
  224. Xof Knuth Vol 3 and a little knowledge of C could type them in as easily
  225. Xas I did, there isn't much point in claiming a copyright, much less
  226. Xapplying for a patent.  I wanted to disclaim liability though, so I put
  227. Xa few minor restrictions on the code, as set forth in each of the
  228. Xsource files.
  229. END_OF_FILE
  230.   if test 7993 -ne `wc -c <'README'`; then
  231.     echo shar: \"'README'\" unpacked with wrong size!
  232.   fi
  233.   # end of 'README'
  234. fi
  235. if test -f 'OPTIMIZING' -a "${1}" != "-c" ; then 
  236.   echo shar: Will not clobber existing file \"'OPTIMIZING'\"
  237. else
  238.   echo shar: Extracting \"'OPTIMIZING'\" \(4452 characters\)
  239.   sed "s/^X//" >'OPTIMIZING' <<'END_OF_FILE'
  240. X
  241. XA brief word about optimizing code, in particular, code that
  242. Xcalls a sorting function.
  243. X
  244. XThe qsort() that comes with most C implementations is fast enough for
  245. Xnearly all purposes.  The sort algorithms in this package are here
  246. Xmostly for intellectual curiousity.  The merge_sort algorithm is
  247. Xsuperior in some ways, mostly that it requires fewer callbacks to the
  248. Xcomparison function, but that alone is no reason to sed -e s/qsort/merge_sort/
  249. Xover all your code.
  250. X
  251. XSome general approaches to consider before borrowing one of these
  252. Xsort algorithms for use in your code, approximately in decreasing
  253. Xorder of effectiveness:
  254. X
  255. X1. run prof or gprof to make sure the sorting is an actual
  256. X   bottleneck; often, reading in the records to be sorted
  257. X   takes more wall clock time than the sort itself and effort
  258. X   spent optimizing the sort is completely pointless.
  259. X
  260. X2. Use your compiler's maximal optimization level when compiling
  261. X   the comparison function.  This can result in a surprising 
  262. X   improvement in performance.
  263. X
  264. X3. Hand optimize the comparison function.  Consider sorting on
  265. X   a "predigested" key that requires less work to compare than 
  266. X   the records themselves.  Make as few calls to other functions 
  267. X   as necessary from within the comparison function.
  268. X
  269. X4. Reduce the size of the items being sorted.  Create an
  270. X   array of pointers to records already existing elsewhere
  271. X   in memory; the sort will then only have to shuffle the
  272. X   pointers around rather than copy entire records.  Works
  273. X   well in combination with #3.
  274. X
  275. X5. Consider maintaining a b-tree or other index which
  276. X   lasts beyond program termination.  If the index is updated
  277. X   infrequently and only one or two elements are added
  278. X   to it at a time, the much-maligned bubble sort might
  279. X   actually be of use.
  280. X
  281. X6. Plug in merge_sort from this package.  Expect only a slight
  282. X   improvement.  But a degradation is possible as well: this merge
  283. X   sort allocates a big chunk of memory, which can eat up swap 
  284. X   space and slow things down.
  285. X
  286. X7. Make a copy of the merge_sort code and replace the calls
  287. X   to the cmpr_func with the actual code of the compare.
  288. X   Or if you have gcc, take advantage of inlining to achieve
  289. X   the same thing.  Expect an even less noticeable improvement.
  290. X
  291. X8. If it's *still too slow*, write a sort that takes advantage
  292. X   of the distribution of keys to calculate the position of a
  293. X   record directly without having to compare it to other records.
  294. X
  295. X
  296. XThe comp.lang.c FAQ list has this to say about the subject of
  297. Xefficiency in general.  "Read it.  Learn it.  Live it."
  298. X
  299. X---------------------------------------------------------------------------
  300. X17.13:  How can I make this code more efficient?
  301. X
  302. XA:      Efficiency, though a favorite comp.lang.c topic, is not
  303. X        important nearly as often as people tend to think it is.  Most
  304. X        of the code in most programs is not time-critical.  When code is
  305. X        not time-critical, it is far more important that it be written
  306. X        clearly and portably than that it be written maximally
  307. X        efficiently.  (Remember that computers are very, very fast, and
  308. X        that even "inefficient" code can run without apparent delay.)
  309. X
  310. X        It is notoriously difficult to predict what the "hot spots" in a
  311. X        program will be.  When efficiency is a concern, it is important
  312. X        to use profiling software to determine which parts of the
  313. X        program deserve attention.  Often, actual computation time is
  314. X        swamped by peripheral tasks such as I/O and memory allocation,
  315. X        which can be sped up by using buffering and cacheing techniques.
  316. X
  317. X        For the small fraction of code that is time-critical, it is
  318. X        vital to pick a good algorithm; it is less important to
  319. X        "microoptimize" the coding details.  Many of the "efficient
  320. X        coding tricks" which are frequently suggested (e.g. substituting
  321. X        shift operators for multiplication by powers of two) are
  322. X        performed automatically by even simpleminded compilers.
  323. X        Heavyhanded "optimization" attempts can make code so bulky that
  324. X        performance is degraded.
  325. X
  326. X        For more discussion of efficiency tradeoffs, as well as good
  327. X        advice on how to increase efficiency when it is important, see
  328. X        chapter 7 of Kernighan and Plauger's The Elements of Programming
  329. X        Style, and Jon Bentley's Writing Efficient Programs.
  330. X---------------------------------------------------------------------------
  331. X
  332. END_OF_FILE
  333.   if test 4452 -ne `wc -c <'OPTIMIZING'`; then
  334.     echo shar: \"'OPTIMIZING'\" unpacked with wrong size!
  335.   fi
  336.   # end of 'OPTIMIZING'
  337. fi
  338. if test -f 'TODO' -a "${1}" != "-c" ; then 
  339.   echo shar: Will not clobber existing file \"'TODO'\"
  340. else
  341.   echo shar: Extracting \"'TODO'\" \(935 characters\)
  342.   sed "s/^X//" >'TODO' <<'END_OF_FILE'
  343. X
  344. Xreturn -1 or something rather than calling assert() in many places
  345. X
  346. Xuse "tag" sort when size of records is so large 
  347. X  that memcpy takes a significant amount of time.
  348. X
  349. Xbetter flow control in flogger; add some command line options
  350. X  for selecting which algorithms to test and which situations
  351. X  to present them with.
  352. X
  353. Xthe check for stable sorting isn't decisive.
  354. X
  355. Xsome of the file names exceed 14 characters
  356. X
  357. Xmake the alignment checking easier to configure (merge and quick sorts)
  358. X
  359. Xmaybe analyze increase in space/time complexity as array size grows
  360. X  and figure out O() empirically.
  361. X
  362. Xinclude file "sorting.h" is of questionable utility.
  363. X
  364. X/usr/lib/lint/llib-lsort might be a nice touch for "make install"
  365. X
  366. Xshould be more flexible about what size and complexity of thing to sort
  367. X
  368. Xmaybe add a parallelizing sort
  369. X
  370. Xmakefile and flogger arent't very portable
  371. X
  372. Xcc -pic is unnecessary when making libsort.a
  373. X
  374. Xadd test for re-entrancy of sort
  375. X
  376. END_OF_FILE
  377.   if test 935 -ne `wc -c <'TODO'`; then
  378.     echo shar: \"'TODO'\" unpacked with wrong size!
  379.   fi
  380.   # end of 'TODO'
  381. fi
  382. if test -f 'flogger.c' -a "${1}" != "-c" ; then 
  383.   echo shar: Will not clobber existing file \"'flogger.c'\"
  384. else
  385.   echo shar: Extracting \"'flogger.c'\" \(16075 characters\)
  386.   sed "s/^X//" >'flogger.c' <<'END_OF_FILE'
  387. X
  388. X/* 
  389. X
  390. XNAME
  391. X  flogger
  392. X
  393. XDESCRIPTION
  394. X
  395. X  Put the sort routines through the paces.  Verify that they actually
  396. X  order data properly and that they don't molest the memory locations
  397. X  immediately above or below the array.  Tries some common worst-case
  398. X  situations like already-ordered data and comparison functions which
  399. X  are defective.
  400. X
  401. X  Prints out estimates for each sort algorithm for usage of heap space,
  402. X  stack space, and run time and also for the number of calls to the
  403. X  comparison function.
  404. X
  405. X  Takes one command line argument which specifies the number of items
  406. X  to put in the array.  Larger values take longer to run.
  407. X
  408. XAUTHORSHIP
  409. X
  410. X  Mike Lee, currently mikey@ontek.com
  411. X
  412. XREFERENCES
  413. X
  414. X  Knuth, Art of Computer Programming Vol 3: Searching and Sorting
  415. X  Kernighan & Richtie, The C Programming Language, Second Edition
  416. X
  417. XWORK REMAINING
  418. X
  419. X  The main loop is hopeless.
  420. X  See the TODO document (which should accompany this program.)
  421. X
  422. XCOPYRIGHT
  423. X
  424. X  Copyright 1992 Michael Lee.
  425. X
  426. X  (1) Permission to use, copy, distribute, and make changes is granted
  427. X  providing that (a) that you do so without charging anyone a fee and
  428. X  (b) this copyright notice must be included verbatim in all copies and 
  429. X  distributions.  
  430. X
  431. X  (2) There is no warranty for this program, to the extent permitted by
  432. X  applicable law.  This program is provided "AS IS" without warranty of
  433. X  any kind, either expressed or implied, including, but not limited to,
  434. X  the implied warranties of merchantability and fitness for a particular 
  435. X  purpose.  The entire risk as to the quality and performance of this 
  436. X  program is with the user.  Should this program prove defective, the 
  437. X  user assumes the cost of all necessary servicing, repair or correction.
  438. X
  439. X  (3) In no event unless required by applicable law will the copyright
  440. X  holder be liable to the user for damages, including any general,
  441. X  special, incidental or consequential damages arising out of the use
  442. X  or inability to use this program (including but not limited to loss of
  443. X  data or data being rendered inaccurate or losses sustained by the
  444. X  user or third parties or a failure of this program to operate with any
  445. X  other programs), even if such holder or third party has been advised
  446. X  of the possibility of such damages.
  447. X
  448. X  (4) Object code produced by a compiler from this code may be 
  449. X  incorporated into commercial products without being subject to 
  450. X  restrictions (1)(a) or (1)(b).
  451. X
  452. X*/
  453. X
  454. X#include <stdio.h>
  455. X#include <malloc.h>
  456. X#include <memory.h>
  457. X#include <string.h>
  458. X#include <signal.h>
  459. X#include <setjmp.h>
  460. X
  461. X#include <sys/types.h>
  462. X#include <sys/times.h>
  463. X#include <sys/param.h>
  464. X
  465. X#include "sorting.h"
  466. X
  467. X#define TEST_TYPE double
  468. X#define TEST_FUNC double_compare
  469. X#define DEFAULT_COUNT 2220 /* product of 4 and several primes */
  470. X
  471. X#define CANARY_LOW -77.0
  472. X#define CANARY_HIGH -88.0
  473. X
  474. X#define TEST_RANDOM 1
  475. X#define TEST_ASCEND 2
  476. X#define TEST_DESCEND 3
  477. X#define TEST_FIB_ASC 4
  478. X#define TEST_FIB_DESC 5
  479. X#define TEST_SURPRISE 6
  480. X#define TEST_MOSTLY 7
  481. X#define TEST_EQUIV 8
  482. X
  483. Xstatic int compare_count;
  484. Xstatic int s_heap;
  485. Xstatic char * s_low, * s_high;
  486. X
  487. X#define CHECK_CANARIES \
  488. X  { \
  489. X    if (*(TEST_TYPE *) a == CANARY_LOW || *(TEST_TYPE *) b == CANARY_LOW)\
  490. X    { \
  491. X      printf("ran off the bottom of the array!\n"); \
  492. X      fflush(stdout); \
  493. X      longjmp(next, 1); \
  494. X    } \
  495. X    if (*(TEST_TYPE *) a == CANARY_HIGH || *(TEST_TYPE *) b == CANARY_HIGH)\
  496. X    { \
  497. X      printf("ran off the top of the array!\n"); \
  498. X      fflush(stdout); \
  499. X      longjmp(next, 1); \
  500. X    } \
  501. X  }
  502. X
  503. X#define UPDATE_S_HEAP \
  504. X  { struct mallinfo mi; \
  505. X    mi = mallinfo();  \
  506. X    if (s_heap < mi.uordblks) s_heap = mi.uordblks;  \
  507. X    if (s_low == NULL || where < s_low) s_low = where; \
  508. X    if (s_high == NULL || where > s_high) s_high = where; \
  509. X    compare_count ++; }
  510. X
  511. Xstatic jmp_buf next;
  512. X
  513. Xvoid catch_quit()
  514. X{
  515. X  printf("\n");
  516. X  fflush(stdout);
  517. X  longjmp(next, 1);
  518. X}
  519. X
  520. Xvoid test_sort_func();
  521. X
  522. Xint int_compare(a, b) int * a, *b; 
  523. X{ 
  524. X  char foo;
  525. X  char * where = &foo;
  526. X
  527. X  CHECK_CANARIES;
  528. X  UPDATE_S_HEAP;
  529. X
  530. X  if (*a > *b) return 1;
  531. X  if (*a < *b) return -1;
  532. X  return 0;
  533. X}
  534. X
  535. Xint double_compare(a, b) double * a, *b; 
  536. X{ 
  537. X  char foo;
  538. X  char * where = &foo;
  539. X
  540. X  CHECK_CANARIES;
  541. X  UPDATE_S_HEAP;
  542. X
  543. X  if (*a > *b) return 1;
  544. X  if (*a < *b) return -1;
  545. X  return 0;
  546. X}
  547. X
  548. X/*ARGSUSED*/
  549. Xint lie_ascending(a, b) char * a, *b; 
  550. X{ 
  551. X  char foo;
  552. X  char * where = &foo;
  553. X
  554. X  CHECK_CANARIES;
  555. X  UPDATE_S_HEAP;
  556. X
  557. X  return -1;
  558. X}
  559. X
  560. X/*ARGSUSED*/
  561. Xint lie_descending(a, b) char * a, *b; 
  562. X{ 
  563. X  char foo;
  564. X  char * where = &foo;
  565. X
  566. X  CHECK_CANARIES;
  567. X  UPDATE_S_HEAP;
  568. X
  569. X  return 1;
  570. X}
  571. X
  572. X/*ARGSUSED*/
  573. Xint lie_equal(a, b) char * a, *b; 
  574. X{ 
  575. X  char foo;
  576. X  char * where = &foo;
  577. X
  578. X  CHECK_CANARIES;
  579. X  UPDATE_S_HEAP;
  580. X
  581. X  return 0;
  582. X}
  583. X
  584. X/*ARGSUSED*/
  585. Xint surprise(a, b) char * a, *b; 
  586. X{ 
  587. X  char foo;
  588. X  char * where = &foo;
  589. X
  590. X  CHECK_CANARIES;
  591. X  UPDATE_S_HEAP;
  592. X
  593. X  foo = rand() >> 23;
  594. X  if ((unsigned char) foo < 85) return -1;
  595. X  if ((unsigned char) foo < 171) return 0;
  596. X  return 1;
  597. X}
  598. X
  599. Xint main(argc, argv) int argc; char * argv[];
  600. X{
  601. X  int n;
  602. X  int stage = 0;
  603. X  int done = 0;
  604. X
  605. X  printf("sort flogger version %d patch level %d.\n",
  606. X    FLOGGER_VERSION, FLOGGER_PATCHLEVEL);
  607. X  if (argc > 1) 
  608. X    n = atoi(argv[1]);
  609. X  else
  610. X    n = DEFAULT_COUNT;
  611. X  if (n < 0) n = -n;
  612. X
  613. X  printf("timer resolution = %1.6f\n", 1.0/(double)HZ);
  614. X  printf("element size = %d\n", sizeof(TEST_TYPE));
  615. X  printf("number of elements = %d", n);
  616. X  fflush(stdout);
  617. X
  618. X  setjmp(next);
  619. X  signal(SIGINT, catch_quit);
  620. X
  621. X  /* apologies for the bizarre code layout */
  622. X
  623. X  while (! done) switch (stage)
  624. X  {
  625. X    case 0: printf("\n*** qsort ***\n");
  626. X            printf("data         compares      stack       ");
  627. X            printf("heap       user       system\n");
  628. X            fflush(stdout);
  629. X            stage ++; test_sort_func(qsort, n, 1); break;
  630. X    case 1: stage ++; test_sort_func(qsort, n, 2); break;
  631. X    case 2: stage ++; test_sort_func(qsort, n, 3); break;
  632. X    case 3: stage ++; test_sort_func(qsort, n, 4); break;
  633. X    case 4: stage ++; test_sort_func(qsort, n, 5); break;
  634. X    case 5: stage ++; test_sort_func(qsort, n, 6); break;
  635. X    case 6: stage ++; test_sort_func(qsort, n, 7); break;
  636. X    case 7: stage ++; test_sort_func(qsort, n, 8); break;
  637. X
  638. X    case 10: _maybe_sorted = 0;
  639. X             printf("\n*** merge_sort ***\n");
  640. X             printf("data         compares      stack       ");
  641. X             printf("heap       user       system\n");
  642. X             fflush(stdout);
  643. X             stage ++; test_sort_func(merge_sort, n, 1); break;
  644. X    case 11: stage ++; test_sort_func(merge_sort, n, 2); break;
  645. X    case 12: stage ++; test_sort_func(merge_sort, n, 3); break;
  646. X    case 13: stage ++; test_sort_func(merge_sort, n, 4); break;
  647. X    case 14: stage ++; test_sort_func(merge_sort, n, 5); break;
  648. X    case 15: stage ++; test_sort_func(merge_sort, n, 6); break;
  649. X    case 16: stage ++; test_sort_func(merge_sort, n, 7); break;
  650. X    case 17: stage ++; test_sort_func(merge_sort, n, 8); break;
  651. X
  652. X    case 20: _maybe_sorted = 1;
  653. X             printf("\n*** merge_sort(_maybe_sorted) ***\n");
  654. X             printf("data         compares      stack       ");
  655. X             printf("heap       user       system\n");
  656. X             fflush(stdout);
  657. X             stage ++; test_sort_func(merge_sort, n, 1); break;
  658. X    case 21: stage ++; test_sort_func(merge_sort, n, 2); break;
  659. X    case 22: stage ++; test_sort_func(merge_sort, n, 3); break;
  660. X    case 23: stage ++; test_sort_func(merge_sort, n, 4); break;
  661. X    case 24: stage ++; test_sort_func(merge_sort, n, 5); break;
  662. X    case 25: stage ++; test_sort_func(merge_sort, n, 6); break;
  663. X    case 26: stage ++; test_sort_func(merge_sort, n, 7); break;
  664. X    case 27: stage ++; test_sort_func(merge_sort, n, 8); break;
  665. X
  666. X    case 30: printf("\n*** heap_sort ***\n");
  667. X             printf("data         compares      stack       ");
  668. X             printf("heap       user       system\n");
  669. X             fflush(stdout);
  670. X             stage ++; test_sort_func(heap_sort, n, 1); break;
  671. X    case 31: stage ++; test_sort_func(heap_sort, n, 2); break;
  672. X    case 32: stage ++; test_sort_func(heap_sort, n, 3); break;
  673. X    case 33: stage ++; test_sort_func(heap_sort, n, 4); break;
  674. X    case 34: stage ++; test_sort_func(heap_sort, n, 5); break;
  675. X    case 35: stage ++; test_sort_func(heap_sort, n, 6); break;
  676. X    case 36: stage ++; test_sort_func(heap_sort, n, 7); break;
  677. X    case 37: stage ++; test_sort_func(heap_sort, n, 8); break;
  678. X
  679. X    case 40: printf("\n*** shell_sort ***\n");
  680. X             printf("data         compares      stack       ");
  681. X             printf("heap       user       system\n");
  682. X             fflush(stdout);
  683. X             stage ++; test_sort_func(shell_sort, n, 1); break;
  684. X    case 41: stage ++; test_sort_func(shell_sort, n, 2); break;
  685. X    case 42: stage ++; test_sort_func(shell_sort, n, 3); break;
  686. X    case 43: stage ++; test_sort_func(shell_sort, n, 4); break;
  687. X    case 44: stage ++; test_sort_func(shell_sort, n, 5); break;
  688. X    case 45: stage ++; test_sort_func(shell_sort, n, 6); break;
  689. X    case 46: stage ++; test_sort_func(shell_sort, n, 7); break;
  690. X    case 47: stage ++; test_sort_func(shell_sort, n, 8); break;
  691. X
  692. X    case 50: printf("\n*** quick_sort ***\n");
  693. X             printf("data         compares      stack       ");
  694. X             printf("heap       user       system\n");
  695. X             fflush(stdout);
  696. X             stage ++; test_sort_func(quick_sort, n, 1); break;
  697. X    case 51: stage ++; test_sort_func(quick_sort, n, 2); break;
  698. X    case 52: stage ++; test_sort_func(quick_sort, n, 3); break;
  699. X    case 53: stage ++; test_sort_func(quick_sort, n, 4); break;
  700. X    case 54: stage ++; test_sort_func(quick_sort, n, 5); break;
  701. X    case 55: stage ++; test_sort_func(quick_sort, n, 6); break;
  702. X    case 56: stage ++; test_sort_func(quick_sort, n, 7); break;
  703. X    case 57: stage ++; test_sort_func(quick_sort, n, 8); break;
  704. X
  705. X    case 60: printf("\n*** insertion_sort ***\n");
  706. X             printf("data         compares      stack       ");
  707. X             printf("heap       user       system\n");
  708. X             fflush(stdout);
  709. X             stage ++; test_sort_func(insertion_sort, n, 1); break;
  710. X    case 61: stage ++; test_sort_func(insertion_sort, n, 2); break;
  711. X    case 62: stage ++; test_sort_func(insertion_sort, n, 3); break;
  712. X    case 63: stage ++; test_sort_func(insertion_sort, n, 4); break;
  713. X    case 64: stage ++; test_sort_func(insertion_sort, n, 5); break;
  714. X    case 65: stage ++; test_sort_func(insertion_sort, n, 6); break;
  715. X    case 66: stage ++; test_sort_func(insertion_sort, n, 7); break;
  716. X    case 67: stage ++; test_sort_func(insertion_sort, n, 8); break;
  717. X
  718. X    case 70: printf("\n*** bubble_sort ***\n");
  719. X             printf("data         compares      stack       ");
  720. X             printf("heap       user       system\n");
  721. X             fflush(stdout);
  722. X             stage ++; test_sort_func(bubble_sort, n, 1); break;
  723. X    case 71: stage ++; test_sort_func(bubble_sort, n, 2); break;
  724. X    case 72: stage ++; test_sort_func(bubble_sort, n, 3); break;
  725. X    case 73: stage ++; test_sort_func(bubble_sort, n, 4); break;
  726. X    case 74: stage ++; test_sort_func(bubble_sort, n, 5); break;
  727. X    case 75: stage ++; test_sort_func(bubble_sort, n, 6); break;
  728. X    case 76: stage ++; test_sort_func(bubble_sort, n, 7); break;
  729. X    case 77: stage ++; test_sort_func(bubble_sort, n, 8); break;
  730. X
  731. X    case 80: if (n >= 15)
  732. X             {
  733. X               stage += 10;   
  734. X               break;        /* algorithm is factorial!  give up! */
  735. X             }
  736. X             printf("\n*** bogo_sort ***\n");
  737. X             printf("data         compares      stack       ");
  738. X             printf("heap       user       system\n");
  739. X             fflush(stdout);
  740. X             stage ++; test_sort_func(bogo_sort, n, 1); break;
  741. X    case 81: stage ++; test_sort_func(bogo_sort, n, 2); break;
  742. X    case 82: stage ++; test_sort_func(bogo_sort, n, 3); break;
  743. X    case 83: stage ++; test_sort_func(bogo_sort, n, 4); break;
  744. X    case 84: stage ++; test_sort_func(bogo_sort, n, 5); break;
  745. X    case 85: stage ++; test_sort_func(bogo_sort, n, 6); break;
  746. X    case 86: stage ++; test_sort_func(bogo_sort, n, 7); break;
  747. X    case 87: stage ++; test_sort_func(bogo_sort, n, 8); break;
  748. X
  749. X    case 90: done = 1;
  750. X
  751. X    default: stage++;
  752. X  }
  753. X
  754. X  return 0;
  755. X}
  756. X
  757. Xvoid test_sort_func(func, n, situation)
  758. X  int             (*func)();
  759. X  int             n;
  760. X  int             situation;
  761. X{
  762. X  unsigned int i;
  763. X  static TEST_TYPE * foo = NULL;
  764. X  TEST_TYPE temp;
  765. X  int (*fp)();
  766. X  int old_heap;
  767. X  struct tms start, finish;
  768. X
  769. X  /* in case of ctrl-c */
  770. X  if (foo != NULL) free((char *) foo);
  771. X
  772. X  foo = (TEST_TYPE *) malloc((n+2) * sizeof(TEST_TYPE));
  773. X  if (foo == NULL)
  774. X  {
  775. X    printf("insufficient memory to conduct test.\n");
  776. X    exit(1);
  777. X  }
  778. X
  779. X  /* store magic values above and below the array so that we
  780. X     can verify the the sort didn't run off either end */
  781. X
  782. X  foo[0] = (TEST_TYPE) CANARY_LOW;
  783. X  foo[n+1] = (TEST_TYPE) CANARY_HIGH;
  784. X
  785. X  srand((int) n);
  786. X
  787. X  /* initialize the contents of the array appropriately for
  788. X     the situation we are presenting to the sort function */
  789. X
  790. X  for (i = 1; i <= n; i ++) 
  791. X  {
  792. X    switch(situation)
  793. X    {
  794. X      case TEST_RANDOM:
  795. X      case TEST_FIB_ASC:
  796. X      case TEST_FIB_DESC:
  797. X      case TEST_SURPRISE:
  798. X        do {
  799. X          foo[i] = rand();
  800. X        } while (foo[i] == CANARY_LOW || foo[i] == CANARY_HIGH);
  801. X      break;
  802. X
  803. X      case TEST_ASCEND:
  804. X      case TEST_MOSTLY: 
  805. X      case TEST_EQUIV: 
  806. X        foo[i] = i;
  807. X      break;
  808. X
  809. X      case TEST_DESCEND: 
  810. X        foo[i] = n - i;
  811. X      break;
  812. X    }
  813. X  }
  814. X
  815. X  if (situation == TEST_MOSTLY && n > 0)
  816. X  {
  817. X    temp = foo[1];
  818. X    foo[1] = foo[n];
  819. X    foo[n] = temp;
  820. X  }
  821. X
  822. X  compare_count = 0;
  823. X  s_low = NULL;
  824. X  s_high = NULL;
  825. X  old_heap = mallinfo().uordblks;
  826. X  s_heap = old_heap;
  827. X
  828. X  switch(situation)
  829. X  {
  830. X    case TEST_RANDOM:   printf("random:   "); fp = TEST_FUNC; break;
  831. X    case TEST_ASCEND:   printf("ascend:   "); fp = TEST_FUNC; break;
  832. X    case TEST_DESCEND:  printf("descend:  "); fp = TEST_FUNC; break;
  833. X    case TEST_FIB_ASC:  printf("fib asc:  "); fp = lie_ascending; break;
  834. X    case TEST_FIB_DESC: printf("fib desc: "); fp = lie_descending; break;
  835. X    case TEST_SURPRISE: printf("surprise: "); fp = surprise;  break;
  836. X    case TEST_MOSTLY:   printf("mostly:   "); fp = TEST_FUNC;  break;
  837. X    case TEST_EQUIV:    printf("equiv:    "); fp = lie_equal;  break;
  838. X    default: fp = NULL; break;
  839. X  }
  840. X
  841. X  fflush(stdout);
  842. X
  843. X  times(&start);
  844. X
  845. X  /* actually call the sort function */
  846. X  (*func)((char *) &foo[1], (int) n, sizeof(TEST_TYPE), fp);
  847. X
  848. X  times(&finish);
  849. X
  850. X/*
  851. X  printf("\n");
  852. X  for (i = 0; i < n; i ++) printf(i % 5 == 4 ? "%11d\n" : "%11d ", foo[i]);
  853. X  printf("\n");
  854. X*/
  855. X
  856. X  /* print out one row of data */
  857. X
  858. X  printf("%11d", compare_count);
  859. X  printf("%11ld", (long) (s_high - s_low));
  860. X  printf("%11d", s_heap - old_heap);
  861. X  printf("%11.2f", 
  862. X    (double) (finish.tms_utime - start.tms_utime) / (double) HZ);
  863. X  printf("%11.2f", 
  864. X    (double) (finish.tms_stime - start.tms_stime) / (double) HZ);
  865. X  fflush(stdout);
  866. X
  867. X  if (mallinfo().uordblks - old_heap != 0)
  868. X    printf(" (%d leak!)", mallinfo().uordblks - old_heap);
  869. X  printf("\n");
  870. X
  871. X  /* check the areas immediately above and immediately below
  872. X     the array for contamination */
  873. X
  874. X  if (foo[0] != CANARY_LOW)
  875. X    printf("wrote before beginning of array!\n");
  876. X
  877. X  if (foo[n+1] != CANARY_HIGH)
  878. X    printf("wrote past end of array!\n");
  879. X
  880. X  /* if appropriate, make sure the data was actually sorted */
  881. X
  882. X  if (situation == TEST_RANDOM || situation == TEST_ASCEND ||
  883. X      situation == TEST_DESCEND || situation == TEST_MOSTLY)
  884. X    for (i = 2; i <= n; i ++)
  885. X    {
  886. X      if ((*TEST_FUNC)(&foo[i], &foo[i-1]) < 0) 
  887. X      {
  888. X        printf("out of order at position %d\n", i);
  889. X        break;
  890. X      }
  891. X    }
  892. X  
  893. X  /* check for sortedness, but for this case it's not an error
  894. X     just the normal behavior of the algorithm */
  895. X
  896. X  if (situation == TEST_EQUIV)
  897. X  {
  898. X    int stable = 1;
  899. X
  900. X    for (i = 2; i <= n && stable; i ++)
  901. X    {
  902. X      if ((*TEST_FUNC)(&foo[i], &foo[i-1]) < 0) stable = 0;
  903. X    }
  904. X
  905. X    if (stable)
  906. X      printf("algorithm appears to be stable.\n");
  907. X    else
  908. X      printf("algorithm is not stable.\n");
  909. X  }
  910. X  
  911. X
  912. X  if (foo != NULL) 
  913. X  {
  914. X    free((char *) foo);
  915. X    foo = NULL;
  916. X  }
  917. X
  918. X  return;
  919. X}
  920. X
  921. END_OF_FILE
  922.   if test 16075 -ne `wc -c <'flogger.c'`; then
  923.     echo shar: \"'flogger.c'\" unpacked with wrong size!
  924.   fi
  925.   # end of 'flogger.c'
  926. fi
  927. if test -f 'heap_sort.c' -a "${1}" != "-c" ; then 
  928.   echo shar: Will not clobber existing file \"'heap_sort.c'\"
  929. else
  930.   echo shar: Extracting \"'heap_sort.c'\" \(4436 characters\)
  931.   sed "s/^X//" >'heap_sort.c' <<'END_OF_FILE'
  932. X
  933. X/* 
  934. X
  935. XNAME
  936. X  heap sort 
  937. X
  938. XDESCRIPTION
  939. X
  940. X  See some of the comments below for a partial description.
  941. X
  942. XAUTHORSHIP
  943. X
  944. X  This version was written by mouse@larry.mcrcim.mcgill.edu
  945. X  who has gracefully given me permission to include it in
  946. X  this package of sort algorithms. 
  947. X
  948. X  The original heapsort is credited to Williams by Knuth and
  949. X  some improvements are credited to Floyd by Standish.
  950. X
  951. XREFERENCES
  952. X
  953. X  J. W. J. Williams, CACM 7 1964
  954. X  R. W. Floyd, Algorithm 245: Treesort 3, CACM 7:12 December, 1964
  955. X  Knuth, Art of Computer Programming Vol 3, page 145ff
  956. X  Thomas A. Standish, Data Structure Techniques, page 91-92
  957. X
  958. XCOMPLEXITY
  959. X
  960. X  O(n log n)
  961. X  Iterative.
  962. X
  963. XCOPYRIGHT
  964. X
  965. X  Questions about the copyright status of should be addressed
  966. X  to the author.
  967. X
  968. X*/
  969. X
  970. X
  971. X#include <stdio.h>
  972. X#include <malloc.h>
  973. X#include <string.h>
  974. X
  975. X/* this is an interface routine that takes a parameter
  976. X   list like qsort's and then calls the real heapsort. */
  977. X   
  978. Xint heap_sort(base, nelem, width, cmpr_func)
  979. X  char * base;
  980. X  int nelem;
  981. X  int width;
  982. X  int (*cmpr_func)();
  983. X{
  984. X  char ** temp_in;
  985. X  char * temp_out;
  986. X  int i;
  987. X
  988. X  temp_in = (char **) malloc(nelem * sizeof(char *));
  989. X  for (i = 0; i < nelem; i++)
  990. X    temp_in[i] = base+i*width;
  991. X
  992. X  heapsort(temp_in, nelem, cmpr_func);
  993. X
  994. X  temp_out = malloc(nelem * width);
  995. X  for (i = 0; i < nelem; i++)
  996. X    memcpy(temp_out+i*width, temp_in[i], width);
  997. X
  998. X  memcpy(base, temp_out, nelem*width);
  999. X
  1000. X  free((char *) temp_in);
  1001. X  free(temp_out);
  1002. X
  1003. X  return 0;
  1004. X}
  1005. X
  1006. X/*
  1007. XFrom uunet!Thunder.McRCIM.McGill.EDU!mouse Fri Nov 20 04:41:30 1992
  1008. XDate: Fri, 20 Nov 92 05:13:19 -0500
  1009. XFrom: der Mouse  <uunet!Thunder.McRCIM.McGill.EDU!mouse>
  1010. XTo: mikey@ontek.com
  1011. XSubject: Re: qucik, merge, shell and bubble sort
  1012. XStatus: R
  1013. X
  1014. X> I'll also be adding heapsort and shellsort algorithms; if anyone has
  1015. X> a qsort-like drop-in replacement for either or both of those I'd
  1016. X> appreciate a copy.
  1017. X
  1018. XNote the interface difference (an extra level of pointers, which is a
  1019. Xbit of a pain because it often means allocating an array of char *),
  1020. Xbut here's a heapsort I've been using.  (I wrote it.)
  1021. X*/
  1022. X
  1023. X#if 0
  1024. Xheapsort(ptrs,nels,cmp)
  1025. Xchar **ptrs; /* should be `<unknown>**ptrs', but no such type exists */
  1026. Xint nels;
  1027. Xint (*cmp)();
  1028. X#endif
  1029. X/*
  1030. X        Sorts the ptrs vector.  (*cmp)(ptrs[i],ptrs[j]) should return:
  1031. X
  1032. X                < 0        if *ptrs[i] < *ptrs[j]
  1033. X                = 0        if *ptrs[i] = *ptrs[j]
  1034. X                > 0        if *ptrs[i] > *ptrs[j]
  1035. X
  1036. X        For example, if the ptrs are actually pointers to int, it would
  1037. X        be perfectly good to write a cmp function as follows (unless the
  1038. X        integers are so large that overflow can occur in the subtraction):
  1039. X
  1040. X                int cmp(p1,p2)
  1041. X                char *p1;
  1042. X                char *p2;
  1043. X                {
  1044. X                 return(*(int *)p1 - *(int *)p2);
  1045. X                }
  1046. X
  1047. X        Tip:  If the ptrs are character string pointers, the standard
  1048. X        strcmp() function is a good cmp function.
  1049. X
  1050. X        The vector will be in non-decreasing order by this criterion on
  1051. X        return from heapsort.
  1052. X*/
  1053. X
  1054. Xstatic _heapsort_bubble_up(size,ptrs,cmp)
  1055. Xint size;
  1056. Xchar **ptrs;
  1057. Xint (*cmp)();
  1058. X{
  1059. X int i;
  1060. X int p;
  1061. X char *temp;
  1062. X
  1063. X i = size;
  1064. X while (1)
  1065. X  { if (i == 0)
  1066. X     { return;
  1067. X     }
  1068. X    p = (i - 1) >> 1;
  1069. X    if ((*cmp)(ptrs[i],ptrs[p]) > 0)
  1070. X     { temp = ptrs[i];
  1071. X       ptrs[i] = ptrs[p];
  1072. X       ptrs[p] = temp;
  1073. X       i = p;
  1074. X     }
  1075. X    else
  1076. X     { return;
  1077. X     }
  1078. X  }
  1079. X}
  1080. X
  1081. Xstatic _heapsort_bubble_down(size,ptrs,cmp)
  1082. Xint size;
  1083. Xchar **ptrs;
  1084. Xint (*cmp)();
  1085. X{
  1086. X int i;
  1087. X int j;
  1088. X int l;
  1089. X int r;
  1090. X int cl;
  1091. X int cr;
  1092. X char *temp;
  1093. X
  1094. X i = 0;
  1095. X while (1)
  1096. X  { if (i >= size)
  1097. X     { return;
  1098. X     }
  1099. X    l = i + i + 1;
  1100. X    r = l + 1;
  1101. X    cl = (l >= size) ? 1 : ((*cmp)(ptrs[i],ptrs[l]) >= 0);
  1102. X    cr = (r >= size) ? 1 : ((*cmp)(ptrs[i],ptrs[r]) >= 0);
  1103. X    switch ((cl<<1)|cr)
  1104. X     { case 0:
  1105. X          j = ((*cmp)(ptrs[l],ptrs[r]) > 0) ? l : r;
  1106. X          break;
  1107. X       case 1:
  1108. X          j = l;
  1109. X          break;
  1110. X       case 2:
  1111. X          j = r;
  1112. X          break;
  1113. X       case 3:
  1114. X          return;
  1115. X     }
  1116. X    temp = ptrs[j];
  1117. X    ptrs[j] = ptrs[i];
  1118. X    ptrs[i] = temp;
  1119. X    i = j;
  1120. X  }
  1121. X}
  1122. X
  1123. Xheapsort(ptrs,nels,cmp)
  1124. Xchar **ptrs;
  1125. Xint nels;
  1126. Xint (*cmp)();
  1127. X{
  1128. X int size;
  1129. X char *temp;
  1130. X
  1131. X if (nels <= 1)
  1132. X  { return;
  1133. X  }
  1134. X size = 1;
  1135. X while (size < nels)
  1136. X  { _heapsort_bubble_up(size,ptrs,cmp);
  1137. X    size ++;
  1138. X  }
  1139. X while (size > 1)
  1140. X  { size --;
  1141. X    temp = ptrs[size];
  1142. X    ptrs[size] = ptrs[0];
  1143. X    ptrs[0] = temp;
  1144. X    _heapsort_bubble_down(size,ptrs,cmp);
  1145. X  }
  1146. X}
  1147. END_OF_FILE
  1148.   if test 4436 -ne `wc -c <'heap_sort.c'`; then
  1149.     echo shar: \"'heap_sort.c'\" unpacked with wrong size!
  1150.   fi
  1151.   # end of 'heap_sort.c'
  1152. fi
  1153. if test -f 'merge_sort.c' -a "${1}" != "-c" ; then 
  1154.   echo shar: Will not clobber existing file \"'merge_sort.c'\"
  1155. else
  1156.   echo shar: Extracting \"'merge_sort.c'\" \(8283 characters\)
  1157.   sed "s/^X//" >'merge_sort.c' <<'END_OF_FILE'
  1158. X
  1159. X/* 
  1160. X
  1161. XNAME
  1162. X  merge sort
  1163. X
  1164. XDESCRIPTION
  1165. X
  1166. X  Divide up the array into halves, then quarters, then eighths and so
  1167. X  on until it can be divided no more.  Perform a "tape merge" on
  1168. X  adjacent sections, building up larger ordered subsections until
  1169. X  you're done.
  1170. X
  1171. X  This version has some nifty features:
  1172. X
  1173. X  1. It avoids mempcy for arrays of 4 byte or 8 bytes, so sorting
  1174. X     pointers, ints, longs, float, doubles, or appropriately size tiny
  1175. X     structures works quickly.  Someday I will add merge2 and merge16
  1176. X     and round out the collection, but beyond that the savings are
  1177. X     questionable.
  1178. X
  1179. X  2. After the merges of subsections become larger than a certain
  1180. X     number of records, a quick check is made to see if the last item
  1181. X     of the first subsection is less than the first item of the second
  1182. X     subsection; in this case the array is already in order there so
  1183. X     there's no point in doing a merge of the two subsections.  This
  1184. X     feature can be turned off by setting _maybe_sorted to 0.
  1185. X
  1186. X  3. Array indexes and pointer math have been simplified to a degree.
  1187. X     A sophisticated compiler would have no trouble performing strength
  1188. X     reduction, but this way some improvement is available even if you
  1189. X     don't cc -O.
  1190. X
  1191. X  4. If it can't malloc the space it needs, it gives up and calls qsort().
  1192. X
  1193. XAUTHORSHIP
  1194. X
  1195. X  Knuth mentions Von Neumann as the first person who implemented a
  1196. X  decent merge sort.  Merge sort as an algorithm probably predates 
  1197. X  electronic computers.
  1198. X
  1199. XREFERENCES
  1200. X
  1201. X  John Von Neumann, Collected Works 5, 1963
  1202. X  Knuth, Art of Computer Programming Vol 3, pg 159-168
  1203. X
  1204. XCOMPLEXITY
  1205. X
  1206. X  O(n log n)
  1207. X
  1208. X  This code is recursive, although the algorithm can be (and often is)
  1209. X  implemented without recursion.
  1210. X
  1211. X  Unlike many sort algorithms, this takes 2n memory.
  1212. X
  1213. XPORTABILITY PROBLEMS
  1214. X
  1215. X  My choice of sizes for special sort functions and for the
  1216. X  MAYBE_THRESHOLD aren't necessarily ideal for all computers
  1217. X  for all time.  
  1218. X  
  1219. X  The alignment check is hopelessly RISC-centric, but easy to remove.
  1220. X
  1221. XCOPYRIGHT
  1222. X
  1223. X  Copyright 1992 Michael Lee.
  1224. X
  1225. X  (1) Permission to use, copy, distribute, and make changes is granted
  1226. X  providing that (a) that you do so without charging anyone a fee and
  1227. X  (b) this copyright notice must be included verbatim in all copies and 
  1228. X  distributions.  
  1229. X
  1230. X  (2) There is no warranty for this program, to the extent permitted by
  1231. X  applicable law.  This program is provided "AS IS" without warranty of
  1232. X  any kind, either expressed or implied, including, but not limited to,
  1233. X  the implied warranties of merchantability and fitness for a particular 
  1234. X  purpose.  The entire risk as to the quality and performance of this 
  1235. X  program is with the user.  Should this program prove defective, the 
  1236. X  user assumes the cost of all necessary servicing, repair or correction.
  1237. X
  1238. X  (3) In no event unless required by applicable law will the copyright
  1239. X  holder be liable to the user for damages, including any general,
  1240. X  special, incidental or consequential damages arising out of the use
  1241. X  or inability to use this program (including but not limited to loss of
  1242. X  data or data being rendered inaccurate or losses sustained by the
  1243. X  user or third parties or a failure of this program to operate with any
  1244. X  other programs), even if such holder or third party has been advised
  1245. X  of the possibility of such damages.
  1246. X
  1247. X  (4) Object code produced by a compiler from this code may be 
  1248. X  incorporated into commercial products without being subject to 
  1249. X  restrictions (1)(a) or (1)(b).
  1250. X
  1251. X*/
  1252. X
  1253. X#include <stdio.h>
  1254. X#include <malloc.h>
  1255. X#include <memory.h>
  1256. X#include <string.h>
  1257. X
  1258. X#include "sorting.h"
  1259. X
  1260. X#ifdef PARANOID
  1261. X#include <assert.h>
  1262. X#endif
  1263. X
  1264. Xint _maybe_sorted = 1;
  1265. X
  1266. Xstatic int merge4();
  1267. Xstatic int merge8();
  1268. Xstatic int mergen();
  1269. X
  1270. Xint merge_sort(base, nelem, width, cmpr_func)
  1271. X  char * base;
  1272. X  int nelem;
  1273. X  int width;
  1274. X  int (*cmpr_func)();
  1275. X{
  1276. X  if (width == sizeof(chunk4) && (int) base % sizeof(chunk4) == 0)
  1277. X    return merge4((chunk4 *) base, nelem, cmpr_func);
  1278. X  else if (width == sizeof(chunk8) && (int) base % sizeof(chunk8) == 0) 
  1279. X    return merge8((chunk8 *) base, nelem, cmpr_func);
  1280. X  else 
  1281. X    return mergen(base, nelem, width, cmpr_func);
  1282. X}
  1283. X
  1284. X
  1285. Xstatic int merge4(base, nelem, cmpr_func)
  1286. X  chunk4 * base;
  1287. X  int nelem;
  1288. X  int (*cmpr_func)();
  1289. X{
  1290. X  int split;
  1291. X  int a, b;
  1292. X  chunk4 * c;
  1293. X  int in_order;
  1294. X  static chunk4 * out = NULL;
  1295. X  int mine = 0;
  1296. X
  1297. X  if (out == NULL)
  1298. X  {
  1299. X    out = (chunk4 *) malloc(nelem * sizeof(chunk4));
  1300. X    if (out == NULL)
  1301. X    {
  1302. X      qsort((char *) base, nelem, sizeof(chunk4), cmpr_func);
  1303. X      return 0;
  1304. X    }
  1305. X    mine = 1;
  1306. X  }
  1307. X
  1308. X  split = (nelem+1) / 2;
  1309. X
  1310. X  if (split > 1) 
  1311. X    (void) merge4(base, split, cmpr_func);
  1312. X  if (nelem - split > 1) 
  1313. X    (void) merge4(base+split, nelem-split, cmpr_func);
  1314. X
  1315. X  if (_maybe_sorted && nelem > MAYBE_THRESHOLD &&
  1316. X      (*cmpr_func)(base+split, base+split-1) >= 0) 
  1317. X  {
  1318. X    if (mine)
  1319. X    {
  1320. X      free((char *) out);
  1321. X      out = NULL;
  1322. X    }
  1323. X    return 0;
  1324. X  }
  1325. X
  1326. X  a = 0; 
  1327. X  b = split;
  1328. X
  1329. X  c = out;
  1330. X
  1331. X  while(a < split)
  1332. X  {
  1333. X    if (b >= nelem)
  1334. X      in_order = 1;
  1335. X    else 
  1336. X      in_order = ((*cmpr_func)(base+a, base+b) <= 0);
  1337. X    
  1338. X    if (in_order)
  1339. X    {
  1340. X      *c = *(base + a);
  1341. X      c ++;
  1342. X      a ++;
  1343. X    }
  1344. X    else
  1345. X    {
  1346. X      *c = *(base + b);
  1347. X      c ++;
  1348. X      b ++;
  1349. X    }
  1350. X
  1351. X#ifdef PARANOID
  1352. X    assert(c - out <= nelem);
  1353. X#endif
  1354. X
  1355. X  }
  1356. X
  1357. X#ifdef PARANOID
  1358. X  assert(c - out <= nelem);
  1359. X#endif
  1360. X
  1361. X  for (a = 0; a < c - out; a ++) base[a] = out[a];
  1362. X
  1363. X  if (mine)
  1364. X  {
  1365. X    free((char *) out);
  1366. X    out = NULL;
  1367. X  }
  1368. X    
  1369. X  return 0;
  1370. X}
  1371. X
  1372. X
  1373. X
  1374. Xstatic int merge8(base, nelem, cmpr_func)
  1375. X  chunk8 * base;
  1376. X  int nelem;
  1377. X  int (*cmpr_func)();
  1378. X{
  1379. X  int split;
  1380. X  int a, b;
  1381. X  chunk8 * c;
  1382. X  int in_order;
  1383. X  static chunk8 * out = NULL;
  1384. X  int mine = 0;
  1385. X
  1386. X  if (out == NULL)
  1387. X  {
  1388. X    out = (chunk8 *) malloc(nelem * sizeof(chunk8));
  1389. X    if (out == NULL)
  1390. X    {
  1391. X      qsort((char *) base, nelem, sizeof(chunk8), cmpr_func);
  1392. X      return 0;
  1393. X    }
  1394. X    mine = 1;
  1395. X  }
  1396. X
  1397. X  split = (nelem+1) / 2;
  1398. X
  1399. X  if (split > 1) 
  1400. X    (void) merge8(base, split, cmpr_func);
  1401. X  if (nelem - split > 1) 
  1402. X    (void) merge8(base+split, nelem-split, cmpr_func);
  1403. X
  1404. X  if (_maybe_sorted && nelem > MAYBE_THRESHOLD &&
  1405. X      (*cmpr_func)(base+split, base+split-1) >= 0) 
  1406. X  {
  1407. X    if (mine) 
  1408. X    {
  1409. X      free((char *) out);
  1410. X      out = NULL;
  1411. X    }
  1412. X    return 0;
  1413. X  }
  1414. X
  1415. X  a = 0; 
  1416. X  b = split;
  1417. X
  1418. X  c = out;
  1419. X
  1420. X  while(a < split)
  1421. X  {
  1422. X    if (b >= nelem)
  1423. X      in_order = 1;
  1424. X    else 
  1425. X      in_order = ((*cmpr_func)(base+a, base+b) <= 0);
  1426. X    
  1427. X    if (in_order)
  1428. X    {
  1429. X      *c = *(base + a);
  1430. X      c ++;
  1431. X      a ++;
  1432. X    }
  1433. X    else
  1434. X    {
  1435. X      *c = *(base + b);
  1436. X      c ++;
  1437. X      b ++;
  1438. X    }
  1439. X
  1440. X#ifdef PARANOID
  1441. X    assert(c - out <= nelem);
  1442. X#endif
  1443. X
  1444. X  }
  1445. X
  1446. X#ifdef PARANOID
  1447. X  assert(c - out <= nelem);
  1448. X#endif
  1449. X
  1450. X  for (a = 0; a < c - out; a ++) base[a] = out[a];
  1451. X    
  1452. X  if (mine)
  1453. X  {
  1454. X    free((char *) out);
  1455. X    out = NULL;
  1456. X  }
  1457. X
  1458. X  return 0;
  1459. X}
  1460. X
  1461. X
  1462. Xstatic int mergen(base, nelem, width, cmpr_func)
  1463. X  char * base;
  1464. X  int nelem;
  1465. X  int (*cmpr_func)();
  1466. X  int width;
  1467. X{
  1468. X  int split, nw, sw;
  1469. X  int a, b;
  1470. X  char * c;
  1471. X  int in_order;
  1472. X  static char * out = NULL;
  1473. X  int mine = 0;
  1474. X
  1475. X  nw = nelem*width;
  1476. X
  1477. X  if (out == NULL)
  1478. X  {
  1479. X    out = (char *) malloc(nw);
  1480. X    if (out == NULL)
  1481. X    {
  1482. X      qsort(base, nelem, width, cmpr_func);
  1483. X      return 0;
  1484. X    }
  1485. X    mine = 1;
  1486. X  }
  1487. X
  1488. X  split = (nelem+1) / 2;
  1489. X  sw = split*width;
  1490. X
  1491. X  if (split > 1) 
  1492. X    (void) mergen(base, split, width, cmpr_func);
  1493. X  if (nelem - split > 1) 
  1494. X    (void) mergen(base+sw, nelem-split, width, cmpr_func);
  1495. X
  1496. X  if (_maybe_sorted && nelem > MAYBE_THRESHOLD &&
  1497. X      (*cmpr_func)(base+sw, base+sw-width) >= 0) 
  1498. X  {
  1499. X    if (mine) 
  1500. X    {
  1501. X      free(out);
  1502. X      out = NULL;
  1503. X    }
  1504. X    return 0;
  1505. X  }
  1506. X
  1507. X  a = 0; 
  1508. X  b = sw;
  1509. X  c = out;
  1510. X
  1511. X  while(a < sw)
  1512. X  {
  1513. X    if (b >= nw)
  1514. X      in_order = 1;
  1515. X    else 
  1516. X      in_order = ((*cmpr_func)(base+a, base+b) <= 0);
  1517. X    
  1518. X    /* todo: try coalescing adjacent iterations into the
  1519. X       same call to memcpy when in_order is the same */
  1520. X
  1521. X    if (in_order)
  1522. X    {
  1523. X      memcpy(c, base+a, width);
  1524. X      c += width;
  1525. X      a += width;
  1526. X    }
  1527. X    else
  1528. X    {
  1529. X      memcpy(c, base+b, width);
  1530. X      c += width;
  1531. X      b += width;
  1532. X    }
  1533. X
  1534. X#ifdef PARANOID
  1535. X    assert(c - out <= nelem * width);
  1536. X#endif
  1537. X
  1538. X  }
  1539. X
  1540. X#ifdef PARANOID
  1541. X  assert(c - out <= nelem * width); 
  1542. X#endif
  1543. X
  1544. X  memcpy(base, out, c - out);
  1545. X
  1546. X  if (mine)
  1547. X  {
  1548. X    free(out);
  1549. X    out = NULL;
  1550. X  }
  1551. X
  1552. X  return 0;
  1553. X}
  1554. END_OF_FILE
  1555.   if test 8283 -ne `wc -c <'merge_sort.c'`; then
  1556.     echo shar: \"'merge_sort.c'\" unpacked with wrong size!
  1557.   fi
  1558.   # end of 'merge_sort.c'
  1559. fi
  1560. if test -f 'quick_sort.c' -a "${1}" != "-c" ; then 
  1561.   echo shar: Will not clobber existing file \"'quick_sort.c'\"
  1562. else
  1563.   echo shar: Extracting \"'quick_sort.c'\" \(5105 characters\)
  1564.   sed "s/^X//" >'quick_sort.c' <<'END_OF_FILE'
  1565. X
  1566. X/*
  1567. X
  1568. XNAME
  1569. X  quicksort, or partition exchange sort
  1570. X
  1571. XDESCRIPTION
  1572. X
  1573. X  Sort by partitioning, then sort the partitions, and so on.
  1574. X
  1575. XAUTHORSHIP
  1576. X
  1577. X  C. A. R. Hoare.
  1578. X  This particular implementation is taken from K&R2.
  1579. X
  1580. XREFERENCES
  1581. X
  1582. X  Hoare, Comp. J. 5, 1962
  1583. X  Knuth, Vol 3, page 114ff
  1584. X  Kernighan & Ritchie The C Programming Language, Revised Edition, pg 87
  1585. X  Standish, Data Structure Techniques pg 23-27
  1586. X  Sedgewick, Implementing Quicksort Programs CACM 21:10 October 1978
  1587. X
  1588. XCOMPLEXITY
  1589. X
  1590. X  Best case O(n log n)
  1591. X  Worse case O(n^2)
  1592. X  Recursive.
  1593. X
  1594. XPORTABILITY PROBLEMS
  1595. X
  1596. X  Same problems as with merge_sort.
  1597. X
  1598. XCOPYRIGHT
  1599. X
  1600. X  Copyright 1992 Michael Lee.
  1601. X
  1602. X  (1) Permission to use, copy, distribute, and make changes is granted
  1603. X  providing that (a) that you do so without charging anyone a fee and
  1604. X  (b) this copyright notice must be included verbatim in all copies and 
  1605. X  distributions.  
  1606. X
  1607. X  (2) There is no warranty for this program, to the extent permitted by
  1608. X  applicable law.  This program is provided "AS IS" without warranty of
  1609. X  any kind, either expressed or implied, including, but not limited to,
  1610. X  the implied warranties of merchantability and fitness for a particular 
  1611. X  purpose.  The entire risk as to the quality and performance of this 
  1612. X  program is with the user.  Should this program prove defective, the 
  1613. X  user assumes the cost of all necessary servicing, repair or correction.
  1614. X
  1615. X  (3) In no event unless required by applicable law will the copyright
  1616. X  holder be liable to the user for damages, including any general,
  1617. X  special, incidental or consequential damages arising out of the use
  1618. X  or inability to use this program (including but not limited to loss of
  1619. X  data or data being rendered inaccurate or losses sustained by the
  1620. X  user or third parties or a failure of this program to operate with any
  1621. X  other programs), even if such holder or third party has been advised
  1622. X  of the possibility of such damages.
  1623. X
  1624. X  (4) Object code produced by a compiler from this code may be 
  1625. X  incorporated into commercial products without being subject to 
  1626. X  restrictions (1)(a) or (1)(b).
  1627. X
  1628. X*/
  1629. X
  1630. X#include <stdio.h>
  1631. X#include <malloc.h>
  1632. X#include <memory.h>
  1633. X#include <string.h>
  1634. X#include <assert.h>
  1635. X
  1636. X#include "sorting.h"
  1637. X
  1638. Xstatic char * copy_buffer = NULL;
  1639. X
  1640. Xstatic int quick_sortn();
  1641. Xstatic int quick_sort4();
  1642. Xstatic int quick_sort8();
  1643. X
  1644. Xint quick_sort(base, nelem, width, cmpr_func)
  1645. X  char * base;
  1646. X  int nelem;
  1647. X  int width;
  1648. X  int (*cmpr_func)();
  1649. X{
  1650. X  copy_buffer = malloc(width); 
  1651. X  assert(copy_buffer != NULL);
  1652. X
  1653. X  if (width == sizeof(chunk4) && (long) base % sizeof(chunk4) == 0) 
  1654. X    quick_sort4((chunk4 *) base, cmpr_func, 0, nelem-1);
  1655. X  else if (width == sizeof(chunk8) && (long) base % sizeof(chunk8) == 0) 
  1656. X    quick_sort8((chunk8 *) base, cmpr_func, 0, nelem-1);
  1657. X  else 
  1658. X    quick_sortn(base, width, cmpr_func, 0, nelem-1);
  1659. X
  1660. X  free(copy_buffer);
  1661. X  copy_buffer = NULL;
  1662. X}
  1663. X
  1664. X
  1665. Xstatic quick_sortn(base, width, cmpr_func, left, right)
  1666. X  char * base;
  1667. X  int width;
  1668. X  int (*cmpr_func)();
  1669. X  int left, right;
  1670. X{
  1671. X  int i, last;
  1672. X  int half = (left+right)/2;
  1673. X
  1674. X  if (left >= right) return;
  1675. X
  1676. X  memcpy(copy_buffer, base+width*left, width);
  1677. X  memcpy(base+width*left, base+width*half, width);
  1678. X  memcpy(base+width*half, copy_buffer, width);
  1679. X
  1680. X  last = left;
  1681. X  for (i = left + 1; i <= right; i++)
  1682. X    if ((*cmpr_func)(base+width*i, base+width*left) < 0)
  1683. X    {
  1684. X      last ++;
  1685. X      if (last == i) continue;
  1686. X      memcpy(copy_buffer, base+width*last, width);
  1687. X      memcpy(base+width*last, base+width*i, width);
  1688. X      memcpy(base+width*i, copy_buffer, width);
  1689. X    }
  1690. X
  1691. X  memcpy(copy_buffer, base+width*left, width);
  1692. X  memcpy(base+width*left, base+width*last, width);
  1693. X  memcpy(base+width*last, copy_buffer, width);
  1694. X
  1695. X  quick_sortn(base, width, cmpr_func, left, last-1);
  1696. X  quick_sortn(base, width, cmpr_func, last+1, right);
  1697. X}
  1698. X
  1699. X
  1700. Xstatic quick_sort4(base, cmpr_func, left, right)
  1701. X  chunk4 * base;
  1702. X  int (*cmpr_func)();
  1703. X  int left, right;
  1704. X{
  1705. X  int i, last; 
  1706. X  chunk4 temp;
  1707. X
  1708. X  if (left >= right) return;
  1709. X
  1710. X  temp = base[left];
  1711. X  base[left] = base[(left+right)/2];
  1712. X  base[(left+right)/2] = temp;
  1713. X
  1714. X  last = left;
  1715. X  for (i = left + 1; i <= right; i++)
  1716. X    if ((*cmpr_func)(&base[i], &base[left]) < 0)
  1717. X    {
  1718. X      last ++;
  1719. X      if (last == i) continue;
  1720. X      temp = base[last];
  1721. X      base[last] = base[i];
  1722. X      base[i] = temp;
  1723. X    }
  1724. X
  1725. X  temp = base[left];
  1726. X  base[left] = base[last];
  1727. X  base[last] = temp;
  1728. X
  1729. X  quick_sort4(base, cmpr_func, left, last-1);
  1730. X  quick_sort4(base, cmpr_func, last+1, right);
  1731. X}
  1732. X
  1733. X
  1734. Xstatic quick_sort8(base, cmpr_func, left, right)
  1735. X  chunk8 * base;
  1736. X  int (*cmpr_func)();
  1737. X  int left, right;
  1738. X{
  1739. X  int i, last; 
  1740. X  chunk8 temp;
  1741. X
  1742. X  if (left >= right) return;
  1743. X
  1744. X  temp = base[left];
  1745. X  base[left] = base[(left+right)/2];
  1746. X  base[(left+right)/2] = temp;
  1747. X
  1748. X  last = left;
  1749. X  for (i = left + 1; i <= right; i++)
  1750. X    if ((*cmpr_func)(&base[i], &base[left]) < 0)
  1751. X    {
  1752. X      last ++;
  1753. X      if (last == i) continue;
  1754. X      temp = base[last];
  1755. X      base[last] = base[i];
  1756. X      base[i] = temp;
  1757. X    }
  1758. X
  1759. X  temp = base[left];
  1760. X  base[left] = base[last];
  1761. X  base[last] = temp;
  1762. X
  1763. X  quick_sort8(base, cmpr_func, left, last-1);
  1764. X  quick_sort8(base, cmpr_func, last+1, right);
  1765. X}
  1766. X
  1767. END_OF_FILE
  1768.   if test 5105 -ne `wc -c <'quick_sort.c'`; then
  1769.     echo shar: \"'quick_sort.c'\" unpacked with wrong size!
  1770.   fi
  1771.   # end of 'quick_sort.c'
  1772. fi
  1773. echo shar: End of archive 1 \(of 2\).
  1774. cp /dev/null ark1isdone
  1775. MISSING=""
  1776. for I in 1 2 ; do
  1777.     if test ! -f ark${I}isdone ; then
  1778.     MISSING="${MISSING} ${I}"
  1779.     fi
  1780. done
  1781. if test "${MISSING}" = "" ; then
  1782.     echo You have unpacked both archives.
  1783.     rm -f ark[1-9]isdone
  1784. else
  1785.     echo You still must unpack the following archives:
  1786.     echo "        " ${MISSING}
  1787. fi
  1788. exit 0
  1789. exit 0 # Just in case...
  1790.