home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / PROG_C / SORTSRCH.ZIP / SORT_SR.TXT
Text File  |  1994-01-19  |  32KB  |  809 lines

  1.  
  2.  
  3.  
  4.  Sorting and Searching
  5. ================================
  6.  
  7.     In the world of computer science perhaps no other tasks are
  8. more fundamental or as extensively analyzed as those of sorting
  9. and of searching.  These routines are used in virtually all
  10. database programs, as well as in compilers, interpreters, and
  11. operating systems.  This lesson introduces the basics of sorting
  12. and searching information.  Because sorting data generally makes
  13. searching the data easier and faster, sorting is discussed first.
  14.  
  15.     Sorting is the process of arranging a set of similar informa-
  16. tion into an increasing or decreasing order.  Specifically, given
  17. a sorted list a of n elements,
  18.  
  19.                  a[1] <= a[2] <= ... <= a[n]
  20.  
  21.     Though ANSI C supplies the standard qsort() function as part
  22. of the standard library, the study and understanding of sorting
  23. is important for three main reasons.  First, a generalized
  24. function like qsort() cannot be applied to all situations.
  25. Second, because qsort() is parameterized to operate on a wide
  26. variety of data, it will run slower than a similar sort that
  27. operates on only one type of data. (The generalization process
  28. inherently increases run time because of the extra processing
  29. time needed to handle various data types.)  Finally, the Quicksort
  30. algorithm (used by qsort()), although very good for the general
  31. case, may not be the best type of sort for specialized situations.
  32.  
  33.     Generally, when information (such as a mailing list) is
  34. sorted, only a portion of that information is used as the sort
  35. key.  This key is used in comparisons, but when an exchange is
  36. made the entire data structure is swapped. In a mailing list, for
  37. example, the ZIP code field might be used as the key, but the
  38. entire address is sorted.  For the sake of simplicity while
  39. developing the various sorting methods, you will be sorting
  40. character arrays. Later, you will learn how to adapt any of these
  41. methods to any type of data structure.
  42.  
  43.     The three general methods that can be used to sort arrays
  44. are:
  45.  
  46.     By exchange
  47.  
  48.     By selection
  49.  
  50.     By insertion
  51.  
  52.     To understand these three methods, imagine a deck of cards.
  53. To sort the cards using exchange, you would spread the cards,
  54. face up, on a table and then proceed to exchange out-of-order
  55. cards until the deck is ordered.
  56.  
  57.     To sort by selection, you would spread the cards on the
  58. table, select the lowest-value card, take it out of the deck, and
  59. hold it in your hand.  Then you would select from the remaining
  60. cards on the table the lowest card and place it behind the one
  61. already in your hand.  This process would continue until all the
  62. cards were in your hand.  Because you always select the lowest
  63. card from those remaining on the table, the cards in your hand
  64. would be sorted when the process was complete.
  65.  
  66.     To sort the cards using insertion, you would hold the cards
  67. in your hand and would take one at a time. As you took cards from
  68. the deck, you would place them into a new deck on the table,
  69. always inserting them in the correct position.  The deck would be
  70. sorted when you had no cards in your hand.
  71.  
  72.     Many different algorithms exist for each of the three sorting
  73. methods.  Each algorithm has its merits, but the general criteria
  74. for judging a sorting algorithm are based on the following
  75. questions:
  76.  
  77.    How fast can it sort information in an average case?
  78.  
  79.    How fast is its best and worst case?
  80.  
  81.    Does it exhibit natural or unnatural behavior?
  82.  
  83.    Does it rearrange elements with equal keys?
  84.  
  85.     How fast a particular algorithm sorts is of great concern.
  86. The speed with which an array can be sorted is directly related
  87. to the number of comparisons and the number of exchanges
  88. (exchanges take more time).  A comparison occurs when one array
  89. element is compared to another.  An exchange happens when two
  90. elements are swapped in the array.  Later in this chapter you will
  91. see that some sorts require an exponential amount of time per
  92. element to sort and some require logarithmic time.
  93.  
  94.     The best- and worst-case run times are important if you
  95. expect to encounter one of these situations frequently.  Often a
  96. sort will have a good average case, but a terrible worst case.
  97.  
  98.     A sort is said to exhibit natural behavior if it works least
  99. when the list is already in order, harder as the list becomes
  100. less ordered, and hardest when a list is in inverse order.  How
  101. hard a sort works is based on the number of comparisons and moves
  102. that must be executed.
  103.  
  104.     To understand the importance of rearranging elements with
  105. equal keys, imagine a database that is sorted on a main key and a
  106. subkey - for example, a mailing list with the ZIP code as the main
  107. key and the last name within the same ZIP code as the subkey.
  108. When a new address is added to the list, and the list sorted
  109. again, you do not want the subkeys (that is, last names within
  110. ZIP codes) to be rearranged. To guarantee this, a sort must not
  111. exchange main keys of equal value.
  112.  
  113.     In the following sections, representative sorts from each
  114. class of sorting algorithms are analyzed to judge their
  115. efficiency.  Later, improved sorting methods are studied.
  116.  
  117.  
  118. The Bubble Sort
  119. ~~~~~~~~~~~~~~~
  120.     The best-known (and most infamous) sort is the Bubble sort.
  121. Its popularity is derived from its catchy name and its simplicity.
  122. For reasons that will become evident, this is one of the worst
  123. sorts ever conceived.
  124.  
  125.     The Bubble sort uses the exchange method of sorting. The
  126. general concept behind the Bubble sort is the repeated
  127. comparisons and, if necessary, exchanges of adjacent elements.
  128. Its name comes from the method's similarity to bubbles in a tank
  129. of water, where each bubble seeks its own level. In this simplest
  130. form of the Bubble sort:
  131.  
  132. /* bubble sort */
  133. void bubble(char item[], int count)
  134. {
  135.   int i, k;
  136.   char t;
  137.  
  138.   for (i = 1; i < count; ++i)
  139.     for (k = count-1; k >= i; --k) {
  140.       if (item[k-1] > item[k]) {
  141.         /* exchange elements */
  142.         t = item[k-1];
  143.         item[k-1] = item[k];
  144.         item[k] = t;
  145.       }
  146.     }
  147. }
  148.  
  149. 'item' is a pointer to the character array to be sorted and
  150. 'count' is the number of elements in the array.
  151.  
  152.     The Bubble sort is driven by two loops. Given that there are
  153. 'count' elements in the array, the outer loop causes the array to
  154. be scanned 'count-1' times. This ensures that, in the worst case,
  155. every element is in its proper position when the function
  156. terminates. The inner loop performs the actual comparisons and
  157. exchanges. (A slightly optimized version of the Bubble sort will
  158. terminate if no exchanges occur, but this also adds another
  159. comparison to each pass through the inner loop.)
  160.  
  161.     This version of the Bubble sort can be used to sort a
  162. character array into ascending order. For example, this short
  163. program sorts a string typed in from the keyboard:
  164.  
  165. #include <stdio.h>
  166. #include <string.h>
  167.  
  168. /* function prototypes */
  169. void bubble(char [], int);
  170.  
  171. void main()
  172. {
  173.   char str[256];
  174.   int  len;
  175.  
  176.   do {
  177.     printf("\nEnter a string:\n");
  178.     printf("(Exit program with an empty string.)\n");
  179.     gets(str);
  180.     len = strlen(str);
  181.     if (len > 0) {
  182.       bubble(str, len);
  183.       printf("Sorted list:\n%s\n", str);
  184.     }
  185.   } while (len > 0);
  186. }
  187.  
  188.     To illustrate how the Bubble sort works, here are the passes
  189. used to sort 'dcab'.
  190.  
  191.         initial:   d c a b
  192.         pass l:    a d c b     ('a' moved to the leftmost)
  193.         pass 2:    a b d c     ('b' moved to the left)
  194.         pass 3:    a b c d     ('c' exchanged with 'd')
  195.  
  196.     When analyzing any sort, you must determine how many
  197. comparisons and exchanges will be performed for the best,
  198. average, and worst case. With the Bubble sort, the number of
  199. comparisons is always the same because the two for loops will
  200. still repeat the specified number of times, whether or not the
  201. list is initially ordered. This means that the Bubble sort will
  202. always perform (n^2-n)/2 comparisons, where n is the number of
  203. elements to be sorted. (There are 6 comparisons in this example.)
  204. The number of exchanges is 0 for the best case - an already
  205. sorted list. The numbers are 3*(n^2-n)/4 for the average case and
  206. 3*(n^2-n)/2 for the worst case. It is beyond the scope of this
  207. course to explain the derivation of these cases, but you can see
  208. that as the list becomes less ordered, the number of elements
  209. that are out of order approaches the number of comparisons.
  210. (Remember, there are three exchanges in a Bubble sort for every
  211. element out of order.) The Bubble sort is said to be an n-squared
  212. algorithm because its execution time is a multiple of the square
  213. of the number of elements. A Bubble sort is bad for a large
  214. number of elements because execution time is directly related to
  215. the number of comparisons and exchanges.
  216.  
  217.     For example, if you ignore the time it takes to exchange any
  218. out-of-position element, and if each comparison takes 0.001
  219. seconds, then sorting 10 elements will take about 0.05 seconds,
  220. sorting 100 elements will take about 5 seconds, and sorting 1000
  221. elements will take about 500 seconds. A 100,000 element sort (the
  222. size of a small telephone book) would take about 5,000,000
  223. seconds, or about 1400 hours - about two months of continuous
  224. sorting!
  225.  
  226. Sorting by Selection
  227. ~~~~~~~~~~~~~~~~~~~~
  228.     A Selectwn sort selects the element with the lowest value
  229. and exchanges that with the first element. Then from the remain-
  230. ing (n-1) elements, the element with the least key is found and
  231. exchanged with the second element, and so forth, up to the last
  232. two elements. For example, if the selection method were to be
  233. used on the array 'bdac', each pass would look like this:
  234.  
  235.         initial:   b d a c
  236.         pass 1:    a d b c   ('a' was selected)
  237.         pass 2:    a b d c   ('b' was selected)
  238.         pass 3:    a b c d   ('c' was selected)
  239.  
  240.     The basic Selection sort is shown here:
  241.  
  242. /* selection sort */
  243. void select(char item[], int count)
  244. {
  245.   int i, j, k;
  246.   char t;
  247.  
  248.   for (i = 0; i < count-1; ++i) {
  249.     k = i;
  250.     t = item[i];
  251.     for (j = i+1; j < count; ++j) {
  252.       if(item[j] < t) {
  253.         k = j;
  254.         t = item[j];
  255.       }
  256.     }
  257.     item[k] = item[i];
  258.     item[i] = t;
  259.   }
  260. }
  261.  
  262.     Unfortunately, the number of comparisons in the Select sort
  263. is the same as the Bubble sort. This means that the Selection
  264. sort requires (n^2-n)/2 comparisons, which makes it too slow for
  265. a large number of items. The number of exchanges for the best
  266. case is 3*(n-1) and for the worst case is n^2/4 + 3*(n-1).
  267.  
  268.     For the best case, if the list is ordered, then only n-1
  269. elements need to be moved, and each move requires three
  270. exchanges. The worst case approximates the number of comparisons.
  271. Although the average case is beyond the scope of this course to
  272. develop. It is n*(ln(n)+e) where e is Euler's constant (about
  273. 0.577216). This means that although the number of comparisons for
  274. both the Bubble sort and the Selection sort is the same, the
  275. number of exchanges in the average case is far less for the
  276. Selection sort.
  277.  
  278. Sorting by Insertion
  279. ~~~~~~~~~~~~~~~~~~~~
  280.     The Insertion sort is the last of the simple sorting
  281. algorithms. The Insertion sort initially sorts the first two
  282. members of the array. Next, the algorithm inserts the third
  283. member into its sorted position in relation to the first two
  284. members. Then, the fourth element is inserted into the list of
  285. three elements. The process continues until all elements have
  286. been sorted. For example, given the array 'dcab', each pass of
  287. the Insertion sort would look like this:
  288.  
  289.         initial:   d c a b
  290.         pass 1:    c d a b     ('c' & 'd' were exchanged)
  291.         pass 3:    a c d b     ('a' moved to the leftmost)
  292.         pass 4:    a b c d     ('b' inserted)
  293.  
  294.     A version of the Insertion sort is shown here:
  295.  
  296. /* sorting by straight insertion */
  297. void insert(char item[], int count)
  298. {
  299.   int i, k;
  300.   char t;
  301.  
  302.   for (i = 1; i < count; ++i) {
  303.     t = item[i];
  304.     k = i-1;
  305.     while (k >= 0 && t < item[k]) {
  306.       item[k+1] = item[k];
  307.       k--;
  308.     }
  309.     item[k+1] = t;
  310.   }
  311. }
  312.  
  313.     Unlike the Bubble sort and the Selection sort, the number of
  314. comparisons that occur while the Insertion sort is used will
  315. depend on how the list is initially ordered. If the list is in
  316. order, then the number of comparisons is (n-1). If the list is in
  317. inverse order, then the number of comparisons is (n^2+n)/2-1,
  318. while its average number of comparisons is (n^2+n-2)/4.
  319.  
  320.     The number of exchanges for each case is as follows:
  321.  
  322.                 best        2*(n-1)
  323.                 average     (n^2+9*n-10)/4
  324.                 worst       (n^2+3*n-4)/2
  325.  
  326.     Therefore, the number for the worst case is as bad as those
  327. for the Bubble and Selection sorts, and for the average case it
  328. is only slightly better.
  329.  
  330.     The Insertion sort does have two advantages, however. First,
  331. it behaves naturally: it works the least when the array is
  332. already sorted and the hardest when the array is sorted in
  333. inverse order. This makes the Insertion sort useful for lists
  334. that are almost in order. Second, it leaves the order of equal
  335. keys unchanged: if a list is sorted using two keys, then it
  336. remains sorted for both keys after an Insertion sort.
  337.  
  338.     Even though the comparisons may be fairly good for certain
  339. sets of data, the fact that the array must always be shifted over
  340. each time an element is placed in its proper location means that
  341. the number of moves can be very significant. However, the
  342. Insertion sort still behaves naturally, with the least exchanges
  343. occurring for an almost sorted list and the most exchanges for an
  344. inversely ordered array.
  345.  
  346. Improved Sorts
  347. ==============
  348.  
  349.     All of the algorithms thus far had the fatal flaw of
  350. executing in n^2 time. For large amounts of data, the sorts would
  351. be slow - in fact, at some point, too slow to use. Every computer
  352. programmer has heard, or told, the horror story of the "sort that
  353. took three days." Unfortunately, these stories are often true.
  354.  
  355.     When a sort takes too long, it may be the fault of the
  356. underlying algorithm. However, a sad commentary is that the first
  357. response is often "write it in assembly code." Although assembler
  358. code will sometimes speed up a routine by a constant factor, if
  359. the underlying algorithm is bad, the sort will be slow no matter
  360. how optimal the coding. Remember, when the run time of a routine
  361. is relative to n^2, increasing the speed of the coding or of the
  362. computer will only cause a slight improvement because the rate at
  363. which the run time increases changes exponentially. Keep in mind
  364. that if something is not fast enough in C code, then it will
  365. generally not be fast enough in assembler. The solution is to use
  366. a better sorting algorithm.
  367.  
  368.     In this section, two excellent sorts are developed. The first
  369. is the Shell sort, and the second is the Quicksort, which is
  370. generally considered the best sorting routine. These sorts run so
  371. fast that if you blink, you will miss them.
  372.  
  373. The Shell Sort
  374. ~~~~~~~~~~~~~~
  375.     The Shell sort is named after its inventor, D.L. Shell.
  376. However, the name seems to have stuck because its method of
  377. operation resembles sea shells piled upon one another.
  378.  
  379.     The general method, derived from the Insertion sort, is based
  380. on diminishing increments. Below gives a diagram of a Shell sort
  381. on the array 'fdacbe'. First, all elements that are three positions
  382. apart are sorted. Then all elements that are two positions apart
  383. are sorted. Finally, all those adjacent to each other are sorted.
  384.  
  385.         initial:  f  d  a  c  b  e
  386.                   ^--------^           exchange
  387.                      ^--------^        exchange
  388.                         ^--------^     no exchange
  389.  
  390.         pass1:    c  b  a  f  d  e
  391.                   ^-----^              exchange
  392.                      ^-----^           no exchange
  393.                         ^-----^        no exchange
  394.                            ^-----^     exchange
  395.  
  396.         pass2:    a  b  c  e  d  f
  397.                            ^--^        exchange
  398.  
  399.         pass3:    a  b  c  d  e  f
  400.  
  401.     It may not be obvious that this method yields good results,
  402. or even that it will sort the array, but it does both. This
  403. algorithm is efficient because each sorting pass involves
  404. relatively few elements, or elements that are already in
  405. reasonable order; therefore each pass increases the order of the
  406. data.
  407.  
  408.     The exact sequence for the increments can be changed. The
  409. only rule is that the last increment must be 1. For example, the
  410. sequence 9, 5, 3, 2, 1 works well and is used in the Shell sort
  411. shown here. Avoid sequences that are powers of 2 because, for
  412. mathematically complex reasons, they reduce the efficiency of the
  413. sorting algorithm. (However, even if you use them, the sort would
  414. still work.)
  415.  
  416. /* a shell sort */
  417. void shell(char item[], int count)
  418. {
  419.   int i, j, k, s, w;
  420.   char x, a[5];
  421.  
  422.   a[0] = 9; a[1] = 5; a[2] = 3; a[3] = 2; a[4] = 1;
  423.   for (w = 0; w < 5; w++) {
  424.     k = a[w]; s = -k;
  425.     for (i = k; i < count; ++i) {
  426.       x = item[i];
  427.       j = i - k;
  428.       if (s == 0) {
  429.         s = -k;
  430.         s++;
  431.         item[s] = x;
  432.       }
  433.       while (x < item[j] && j >= 0 && j <= count) {
  434.         item[j+k] = item[j];
  435.         j -= k;
  436.       }
  437.       item[j+k] = x;
  438.     }
  439.   }
  440. }
  441.  
  442.     You may have noticed that the inner while loop has three test
  443. conditions. The 'x < item[j]' is a comparison necessary for the
  444. sorting process. The tests 'j >= 0' and 'j <= count' are used to
  445. keep the sort from overrunning the boundary of the array 'item'.
  446. These extra checks degrade the performance of Shell sort to some
  447. extent. Slightly different versions of the Shell sort employ spe-
  448. cial array elements, called sentinels, which are not actually
  449. part of the array to be sorted. Sentinels hold special
  450. termination values that indicate the least and greatest possible
  451. elements. In this way the boundary checks are unnecessary.
  452. However, using sentinels requires a specific knowledge of the
  453. data, which limits the generality of the sort function.
  454.  
  455.     The analysis of the Shell sort presents some very difficult
  456. mathematical problems that are far beyond the scope of this text.
  457. However, execution time is proportional to n^l.2 for sorting n
  458. elements. This is a very significant improvement over the n^2
  459. sorts of the previous section. However, before you decide to use
  460. the Shell sort, you should know that the Quicksort is even
  461. hetter.
  462.  
  463.  
  464. The Quicksort
  465. ~~~~~~~~~~~~~
  466.     The Quicksort, invented and named by C.A.R. Hoare, is
  467. generally considered the best sorting algorithm currently
  468. available. It is based on the exchange method of sorting. This is
  469. surprising if you consider the terrible performance of the Bubble
  470. sort, which is also based on the exchange method.
  471.  
  472.     The Quicksort is built on the idea of partitions. The general
  473. procedure is to select a value (called the comparand) and then to
  474. partition the array into two parts with all elements greater than
  475. or equal to the partition value on one side and those less than
  476. the partition value on the other. This process is then repeated
  477. for each remaining part until the array is sorted. For example,
  478. given the array 'fedacb' and using the value 'd', the first pass
  479. of the Quicksort would rearrange the array like this:
  480.  
  481.         initial:   f e d | a c b
  482.                        ^------------ the comparand
  483.         pass 1:    b c a | d e f
  484.  
  485.     This process is then repeated for each half ('bca' and
  486. 'def'). The process is essentially recursive; indeed, the
  487. cleanest implementations of Quicksort are recursive algorithms.
  488.  
  489.     The selection of the middle comparand value can be
  490. accomplished two ways. The value can be chosen either at random
  491. or by averaging a small set of values taken from the array. For
  492. the optimal sorting it is desirable to select a value that is
  493. precisely in the middle of the range of values. However, this is
  494. not easy to do for most sets of data. Even in the worst case - the
  495. value chosen is at one extremity - Quicksort still performs well.
  496.  
  497.     The following version of Quicksort selects the middle element
  498. of the array. Although this may not always result in a good
  499. choice, the sort still performs correctly.
  500.  
  501. /* quicksort set up */
  502. void quick(char item[], int count)
  503. {
  504.   qs(item, 0, count-1);
  505. }
  506.  
  507. /* quicksort */
  508. void qs(char item[], int left, int right)
  509. {
  510.   int i, j;
  511.   char x, y;
  512.  
  513.   i = left; j = right;
  514.   x = item[(left+right)/2];
  515.  
  516.   do {
  517.     while (item[i] < x && i < right) i++;
  518.     while (x < item[j] && j > left)  j--;
  519.     if (i <= j) {
  520.       y = item[i];
  521.       item[i] = item[j];
  522.       item[j] = y;
  523.       i++; j--;
  524.     }
  525.   } while (i <= j);
  526.   if (left < j)  qs(item, left, j);
  527.   if (i < right) qs(item, i, right);
  528. }
  529.  
  530.  
  531.     In this version, the function quick() sets up a call to the
  532. main sorting function, called qs(). While this maintains the same
  533. common interface of 'item' and 'count', it is not essential
  534. because qs() could have been called directly using three
  535. arguments.
  536.  
  537.     The derivation of the number of comparisons and number of
  538. exchanges that Quicksort performs requires mathematics beyond the
  539. scope of this text. However, you can assume that the number of
  540. comparisons is n*log(n) and that the number of exchanges is
  541. approximately n*log(n)/6. These are significantly better than any
  542. of the previous sorts discussed so far.
  543.  
  544.     The equation
  545.                           N = 10^x
  546.  
  547. can be rewritten as
  548.                           x = log(N)
  549.  
  550.     This means, for example, that if 100 elements were to be
  551. sorted, Quicksort would require 100 * 2, or 200, comparisons
  552. because log 100 is 2. Compared with the Bubble sort's 4950
  553. comparisons, this number is quite good.
  554.  
  555.     You should be aware of one particularly nasty aspect to
  556. Quicksort. If the comparand value for each partition happens to
  557. be the largest value, then Quicksort degenerates into "slowsort"
  558. with an n^2 run time. Generally, however, this does not happen.
  559.  
  560.     You must carefully choose a method of determining the value
  561. of the comparand. Often the value is determined by the actual
  562. data you are sorting. In large mailing lists where the sorting is
  563. often by ZIP code, the selection is simple, because the ZIP codes
  564. are fairly evenly distributed and a simple algebraic function can
  565. determine a suitable comparand. However, in certain databases,
  566. the sort keys may be so close in value (with many being the same
  567. value) that a random selection is often the best method
  568. available. A common and fairly effective method is to sample
  569. three elements from a partition and take the middle value.
  570.  
  571.     Generally, the Quicksort is the sort of choice because it is
  572. so fast. However, when only very small lists of data are to be
  573. sorted (less than 100), the overhead created by Quicksort's
  574. recursive calls may offset the benefits of a superior algorithm.
  575. In rare cases like this, one of the simpler sorts (perhaps even
  576. the Bubble sort) will be quicker.
  577.  
  578.  
  579. Sorting Other Data Structures
  580. =============================
  581.  
  582.     Until now, you have only been sorting arrays of characters.
  583. This has made it easy to present each of the sorting routines.
  584. Obviously, arrays of any of the built-in data types can be sorted
  585. simply by changing the data types of the parameters and variables
  586. to the sort function. However, generally complex data types like
  587. strings, or groupings of information like structures, need to be
  588. sorted. Most sorting involves a key and information linked to
  589. that key. To adapt the algorithms to sort other structures, you
  590. need to alter either the comparison section or the exchange
  591. section, or both. The algorithm itself will remain unchanged.
  592.  
  593.     Because Quicksort is one of the best general-purpose routines
  594. available at this time, it will be used in the following
  595. examples. The same techniques will apply to any of the sorts
  596. described earlier.
  597.  
  598. Sorting strings
  599. ~~~~~~~~~~~~~~~
  600.     The easiest way to sort strings is to create an array of
  601. character pointers to those strings. This allows you to maintain
  602. easy indexing and keeps the basic Quicksort algorithm unchanged.
  603. The string version of Quicksort shown here will accept an array
  604. of char pointers that point to the strings to be sorted. The sort
  605. rearranges the pointers to the strings, not the actual strings in
  606. memory. This version sorts the strings in alphabetical order.
  607.  
  608. /* quick sort for strings setup */
  609. void quick_string(char *item[], int count)
  610. {
  611.    qs_string(item, 0, count-1);
  612. }
  613.  
  614. /* quick sort for strings */
  615. void qs_string(char *item[], int left, int right)
  616. {
  617.   int i, j;
  618.   char *x, *y;
  619.  
  620.   i = left; j = right;
  621.   x = item[(left+right)/2];
  622.   do {
  623.     while (strcmp(item[i], x) < 0 && i < right) i++;
  624.     while (strcmp(item[j], x) > 0 && j > left) j--;
  625.     if (i <= j) {
  626.       y = item[i];
  627.       item[i] = item[j];
  628.       item[j] = y;
  629.     }
  630.   } while (i <= j);
  631.   if (left < j) qs_tring(item, left, j);
  632.   if (i < right) qs_string(item, i, right);
  633. }
  634.  
  635.     The comparison step has been changed to use the function
  636. strcmp(), which returns a negative number if the first string is
  637. lexicographically less than the second, 0 if the strings are
  638. equal, and a positive number if the first string is
  639. lexicographically greater than the second. The exchange part of
  640. the routine has been left unchanged because only the pointers are
  641. being exchanged - not the actual strings. To exchange the actual
  642. strings, you would have to use the function strcpy().
  643.  
  644.     The use of strcmp() will slow down the sort for two reasons.
  645. First, it involves a function call, which always takes time;
  646. second, the strcmp() function itself performs several comparisons
  647. to determine the relationship of the two strings. If speed is
  648. absolutely critical, the code for strcmp() can be duplicated
  649. in-line inside the routine. However, there is no way to avoid
  650. comparing the strings, since this is by definition what the task
  651. involves.
  652.  
  653. Sorting Structures
  654. ~~~~~~~~~~~~~~~~~~
  655.     Most application programs that require a sort will need to
  656. have a grouping of data sorted. A mailing list is an excellent
  657. example because a name, street, city, state, and ZIP code are all
  658. linked together. When this conglomerate unit of data is sorted, a
  659. sort key is used, but the entire structure is exchanged. To see
  660. how this is done, you first need to create a structure. For the
  661. mailing-list example, a convenient structure is
  662.  
  663. struct address {
  664.   char name[40];
  665.   char street[40];
  666.   char city[20];
  667.   char state[3];
  668.   char zip[10];
  669. };
  670.  
  671.     The 'state' is three characters long and 'zip' is ten
  672. characters long because a string array always needs to be one
  673. character longer than the maximum length of any string in order
  674. to store the null terminator.
  675.  
  676.     Since it is reasonable to arrange a mailing list as an array
  677. of structures, assume for this example that the sort routine
  678. sorts an array of structures of type 'address', as shown here.
  679.  
  680. void quick_struct(struct address [], int);
  681. void qs_struct(struct address [], int, int);
  682.  
  683. /* quick sort for structures setup */
  684. void quick_struct(struct address item[], int count)
  685. {
  686.   qs_struct(item, 0, count-1);
  687. }
  688.  
  689. /* quick sort for structures */
  690. void qs_struct(struct address item[], int left, int right)
  691. {
  692.   int i, j;
  693.   char *x, *y;
  694.  
  695.   i = left; j = right;
  696.   x = item[(left+right)/2].zip;
  697.   do {
  698.     while (strcmp(item[i].zip, x) < 0 && i < right) i++;
  699.     while (strcmp(item[j].zip, x) > 0 && j > left) j--;
  700.     if (i <= j) {
  701.       swap_all_fields(item, i, j);
  702.       i++; j--;
  703.     }
  704.   } while (i <= j);
  705.   if (left < j) qs_struct(item, left, j);
  706.   if (i < right) qs_struct(item, i, right);
  707. }
  708.  
  709.     Notice that both the comparison code and the exchange code
  710. needed to be altered. Because so many fields needed to be
  711. exchanged, a separate function, swap_all_fields(), was created to
  712. do this. You will need to create swap_ all_fields() in accordance
  713. with the nature of the structure being sorted.
  714.  
  715.  
  716.  
  717. Searching Methods
  718. =================
  719.  
  720.     Databases of information exist so that, from time to time, a
  721. user can locate a record by knowing its key. There is only one
  722. method of finding information in an unsorted file or array, and
  723. another for a sorted file or array. Many compilers supply
  724. search functions as part of the standard library. However, as
  725. with sorting, general-purpose routines sometimes are simply too
  726. inefficient for use in demanding situations because of the extra
  727. overhead created by the generalization.
  728.  
  729.     Finding information in an unsorted array requires a
  730. sequential search starting at the first element and stopping
  731. either when a match is found or when the end of the array is
  732. reached. This method must be used on unsorted data, but can also
  733. be applied to sorted data. If the data has been sorted, then a
  734. binary search can be used, which greatly speeds up any search.
  735.  
  736. The Sequential Search
  737. ~~~~~~~~~~~~~~~~~~~~~
  738.     The sequential search is easy to code. The following function
  739. searches a character array of known length until a match is found
  740. with the specified key.
  741.  
  742.  
  743. int sequential_search(char item[], int count, char key)
  744. {
  745.    int i;
  746.    for (i = 0; i < count; ++i)
  747.      if (key == item[i]) return (i);
  748.    return (-1);   /* no match */
  749. }
  750.  
  751.     This function will return the index number of the matching
  752. entry if there is one, or -1 if there is not.
  753.  
  754.    A straight sequential search will, on the average, test n/2
  755. elements. In the best case, it will test only one element and in
  756. the worst case n elements. If the information is stored on disk,
  757. the search time can be very long. But if the data is unsorted,
  758. this is the only method available.
  759.  
  760. The Binary Search
  761. ~~~~~~~~~~~~~~~~~
  762.     If the data to be searched is in sorted order, then a
  763. superior method, called the binary search, can be used to find a
  764. match. The method uses the "divide-and-conquer" approach. It
  765. first tests the middle element; if the element is larger than the
  766. key, it then tests the middle element of the first half;
  767. otherwise, it tests the middle element of the second half This
  768. process is repeated until either a match is found, or there are
  769. no more elements to test.
  770.  
  771.     For example, to find the number 4 in the array
  772.  
  773.                       1 2 3 4 5 6 7 8 9
  774.  
  775. the binary search would first test the middle, which is 5.
  776. Since this is greater than 4, the search would continue with the
  777. first half, or
  778.  
  779.                       1 2 3 4 5
  780.  
  781.     In this example, the middle element is 3. This is less than
  782. 4, so the first half is discarded and the search continues with
  783.  
  784.                             4 5
  785.  
  786. This time the match is found.
  787.  
  788.     In the binary search, the number of comparisons given the
  789. worst case is log2(n). With average cases, the number is somewhat
  790. better; in the best case, the number is 1.
  791.  
  792.     A binary search function for character arrays is shown here.
  793. You can make this search any arbitrary data structure by changing
  794. the comparison portion of the routine.
  795.  
  796. /* Binary search */
  797. int binary(char item[], int count, char key)
  798. {
  799.   int low, high, mid;
  800.  
  801.   low = 0; high = count-1;
  802.   while(low <= high) {
  803.     mid = (low+high) / 2;
  804.     if (key < item[mid]) high = mid - 1;                                                  
  805.     else if( key > item[mid]) low = mid + 1;
  806.     else return (mid);   /* found */
  807.   }
  808.   return (-1);
  809.