home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / c / msc51 / example / sortdemo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-11  |  24.8 KB  |  816 lines

  1. /*                   SORTDEMO
  2.  * This    program    graphically demonstrates six common sorting algorithms.     It
  3.  * prints 25 or    43 horizontal bars, all    of different lengths and all in    random
  4.  * order, then sorts the bars from smallest to longest.
  5.  *
  6.  * The program also uses SOUND statements to generate different    pitches,
  7.  * depending on    the location of    the bar    being printed. Note that the SOUND
  8.  * statements delay the    speed of each sorting algorithm    so you can follow
  9.  * the progress    of the sort. Therefore,    the times shown    are for    comparison
  10.  * only. They are not an accurate measure of sort speed.
  11.  *
  12.  * If you use these sorting routines in    your own programs, you may notice
  13.  * a difference    in their relative speeds (for example, the exchange
  14.  * sort    may be faster than the shell sort) depending on    the number of
  15.  * elements to be sorted and how "scrambled" they are to begin with.
  16.  *
  17.  * To build a statically linked    version, use this command line:
  18.  *
  19.  *   CL    /Lp /Zp    sortdemo.c
  20.  *
  21.  * If you wish to be able to run in either real    or protect mode, bind
  22.  * with    the following command line:
  23.  *
  24.  *   BIND sortdemo.exe \lib\doscalls.lib \lib\api.lib \lib\apilmr.obj
  25.  *
  26.  * To build a dynamically linked version, make sure you    have the following
  27.  * files:
  28.  *  
  29.  *   CRTLIB.DLL       Dynamic link    library    in LIBPATH directory
  30.  *   CRTLIB.LIB       Imports library in LIB directory
  31.  *   CTREXE.OBJ       Startup code    for .EXE files in LIB directory
  32.  *  
  33.  * See MTDYNA.DOC for details on creating and using these files. Then use
  34.  * the following command lines:
  35.  *
  36.  *   CL    /c /X /I\include\mt /Alfw /Gs2 /DDLL /Zp sortdemo.c
  37.  *   LINK sortdemo \lib\crtexe /NOI /NOD,,,crtlib doscalls;
  38.  */
  39. #define    INCL_NOCOMMON
  40. #define    INCL_DOSPROCESS
  41. #define    INCL_DOSDATETIME
  42. #define    INCL_SUB
  43. #include <os2.h>
  44. #include <string.h>
  45. #include <stdio.h>
  46. #include <ctype.h>
  47. #include <math.h>
  48. #include <malloc.h>
  49.  
  50. /* Declare data    types for colored bars and cells:
  51.  */
  52. struct SortType    {
  53.     int        Length;        /* Bar length (the element compared
  54.                  * in the different    sorts)           */
  55.     char    ColorVal;        /* Bar color               */
  56. };
  57.  
  58. struct CELLINFO    {
  59.     char    Char;
  60.     char    Attr;
  61. };
  62.  
  63. /* Declare function prototypes:
  64.  */
  65. int  main (void);
  66. void BoxInit (void);
  67. void BubbleSort    (void);
  68. void DrawFrame (int Top, int Left, int Width, int Height);
  69. void ElapsedTime (int CurrentRow);
  70. void ExchangeSort (void);
  71. void HeapSort (void);
  72. void Initialize    (void);
  73. void InsertionSort (void);
  74. void PercolateDown (int    MaxLevel);
  75. void PercolateUp (int MaxLevel);
  76. void PrintOneBar (int Row);
  77. void QuickSort (int Low, int High);
  78. int  RandInt (int Lower, int Upper);
  79. void Reinitialize (void);
  80. void ShellSort (void);
  81. int  Screen (int ACTION);
  82. void SortMenu (void);
  83. void SwapBars (int Row1, int Row2);
  84. void Cls (void);
  85. void Swaps (struct SortType *one, struct SortType *two);
  86.  
  87. /* Declare global constants:
  88.  */
  89. #define    BLOCK        223
  90. #define    TRUE        1
  91. #define    FALSE        0
  92. #define    SAVE        TRUE
  93. #define    SPACECELL   0x0720
  94. #define    RESTORE        FALSE
  95. #define    FIRSTMENU   2
  96. #define    LEFTCOLUMN  48
  97. #define    WIDTH        80 - LEFTCOLUMN
  98. #define    WHITE        0x0f
  99.  
  100. /* Declare global variables:
  101.  */
  102. DATETIME sTime,    wTime;
  103. KBDKEYINFO inChar;
  104. VIOMODEINFO wMode = { sizeof (wMode) };
  105.  
  106. struct SortType    SortArray[44], SortBackup[44];
  107. long oTime, nTime;
  108. int Sound, Pause;
  109. int curSelect;
  110.  
  111. char *Menu[] = {
  112.     "       C Sorting Demo",
  113.     " ",
  114.     "Insertion",
  115.     "Bubble",
  116.     "Heap",
  117.     "Exchange",
  118.     "Shell",
  119.     "Quick",
  120.     " ",
  121.     "Toggle Sound: ",
  122.     " ",
  123.     "Pause Factor: ",
  124.     "<   (Slower)",
  125.     ">   (Faster)",
  126.     " ",
  127.     "Type first character of",
  128.     "choice ( I B H E S Q T < > )",
  129.     "or ESC key to end program: "
  130. };
  131. int Nlines = sizeof (Menu) / sizeof (Menu[0]);
  132.  
  133. main ()
  134. {
  135.     Screen (SAVE);
  136.     VioGetMode (&wMode,    0);
  137.     if (wMode.row != 43) {        /* Use 43-line mode if available */
  138.     wMode.row = 43;
  139.     wMode.hres = 640;        /* Try VGA */
  140.     wMode.vres = 350;
  141.     if (VioSetMode (&wMode,    0)) {
  142.         wMode.hres = 720;        /* Try EGA */
  143.         wMode.vres = 400;
  144.         if (VioSetMode (&wMode, 0))    {
  145.         VioGetMode (&wMode, 0);
  146.         wMode.row = 25;        /* Use 25 lines    */
  147.         VioSetMode (&wMode, 0);
  148.         }
  149.     }
  150.     }
  151.     Initialize ();       /* Initialize data values. */
  152.     SortMenu ();       /* Print sort menu. */
  153.     if (!Screen    (RESTORE))
  154.     Cls ();
  155.     exit (0);
  156. }
  157.  
  158. /* =============================== BoxInit ====================================
  159.  *    Calls the    DrawFrame procedure to draw the    frame around the sort menu,
  160.  *    then prints the different    options    stored in the OptionTitle array.
  161.  * ============================================================================
  162.  */
  163. void BoxInit ()
  164. {
  165.     int    i;
  166.     char Color = WHITE,    Factor[3];
  167.  
  168.     DrawFrame (1, LEFTCOLUMN - 3, WIDTH    + 3, 22);
  169.  
  170.     for    (i = 0;    i < Nlines; i++)
  171.     VioWrtCharStrAtt (Menu[i], strlen (Menu[i]),
  172.              FIRSTMENU + i,    LEFTCOLUMN, &Color, 0);
  173.  
  174.    /* Print the    current    value for Sound:
  175.     */
  176.     if (Sound)
  177.     VioWrtCharStrAtt ("ON ", 3, 11,    LEFTCOLUMN + 14, &Color, 0);
  178.     else
  179.     VioWrtCharStrAtt ("OFF", 3, 11,    LEFTCOLUMN + 14, &Color, 0);
  180.  
  181.     sprintf (Factor,"%3.3u", Pause/30);
  182.     VioWrtCharStrAtt (Factor, 3, 13, LEFTCOLUMN    + 14, &Color, 0);
  183.  
  184.    /* Erase the    speed option if    the length of the Pause    is at a    limit
  185.     */
  186.     if (Pause == 900)
  187.     VioWrtCharStrAtt ("            ", 12, 14, LEFTCOLUMN, &Color, 0);
  188.     if (Pause == 0)
  189.     VioWrtCharStrAtt ("            ", 12, 15, LEFTCOLUMN, &Color, 0);
  190. }
  191.  
  192. /* ============================== BubbleSort ==================================
  193.  *    The BubbleSort algorithm cycles through SortArray, comparing adjacent
  194.  *    elements and swapping pairs that are out of order.  It continues to
  195.  *    do this until no pairs are swapped.
  196.  * ============================================================================
  197.  */
  198. void BubbleSort    ()
  199. {
  200.     int    Row, Switch, Limit;
  201.  
  202.     Limit = wMode.row;
  203.     do {
  204.     Switch = FALSE;
  205.     for (Row = 1; Row <= (Limit - 1); Row++) {
  206.  
  207.        /* Two adjacent elements are    out of order, so swap their values
  208.         * and redraw those two bars: */
  209.         if (SortArray[Row].Length >    SortArray[Row +    1].Length) {
  210.         Swaps (&SortArray[Row],    &SortArray[Row + 1]);
  211.         SwapBars (Row, Row + 1);
  212.         Switch = Row;
  213.         }
  214.     }
  215.  
  216.     /* Sort on next pass only to where the last    switch was made: */
  217.     Limit = Switch;
  218.     } while (Switch);
  219. }
  220.  
  221. /* ============================== DrawFrame ===================================
  222.  *   Draws a rectangular frame using the high-order ASCII characters ╔ (201) ,
  223.  *   ╗ (187) , ╚ (200) , ╝ (188) , ║ (186) , and ═ (205). The parameters
  224.  *   TopSide, BottomSide, LeftSide, and    RightSide are the row and column
  225.  *   arguments for the upper-left and lower-right corners of the frame.
  226.  * ============================================================================
  227.  */
  228. void DrawFrame (int Top, int Left, int Width, int Height)
  229. {
  230. #define    ULEFT 201
  231. #define    URIGHT 187
  232. #define    LLEFT 200
  233. #define    LRIGHT 188
  234. #define    VERTICAL 186
  235. #define    HORIZONTAL 205
  236. #define    SPACE ' '
  237.  
  238.     int     Row;
  239.     char Color = WHITE,    TempStr[80];
  240.  
  241.     memset (TempStr, HORIZONTAL, Width);
  242.     TempStr[0] = ULEFT;
  243.     TempStr[Width - 1] = URIGHT;
  244.  
  245.     VioWrtCharStrAtt (TempStr, Width, Top, Left, &Color, 0);
  246.  
  247.     memset (TempStr, SPACE, Width);
  248.     TempStr[0] = VERTICAL;
  249.     TempStr[Width - 1] = VERTICAL;
  250.  
  251.     for    (Row = Top + 1;    Row <= Height -    1; Row++)
  252.     VioWrtCharStrAtt (TempStr, Width, Row, Left, &Color, 0);
  253.  
  254.     memset (TempStr, HORIZONTAL, Width + 1);
  255.     TempStr[0] = LLEFT;
  256.     TempStr[Width - 1] = LRIGHT;
  257.  
  258.     VioWrtCharStrAtt (TempStr, Width, Top + Height - 1,    Left, &Color, 0);
  259. }
  260.  
  261. /* ============================= ElapsedTime ==================================
  262.  *    Prints seconds elapsed since the given sorting routine started.
  263.  *    Note that    this time includes both    the time it takes to redraw the
  264.  *    bars plus    the pause while    the SOUND statement plays a note, and
  265.  *    thus is not an accurate indication of sorting speed.
  266.  * ============================================================================
  267.  */
  268. void ElapsedTime (int CurrentRow)
  269. {
  270.  
  271.     char Color = WHITE,    Timing[80];
  272.  
  273.     DosGetDateTime (&wTime);
  274.  
  275.     nTime = (wTime.hours * 360000) +
  276.         (wTime.minutes * 6000) +
  277.         (wTime.seconds * 100) +
  278.          wTime.hundredths;
  279.  
  280.     sprintf (Timing, "%7.2f", ((float)(nTime - oTime) /    100));
  281.  
  282.     /* Print the number    of seconds elapsed */
  283.     VioWrtCharStrAtt (Timing, strlen (Timing), curSelect + FIRSTMENU + 2,
  284.     LEFTCOLUMN + 15, &Color, 0);
  285.  
  286.     if (Sound)
  287.     DosBeep    (60 * CurrentRow, 32);     /* Play a note. */
  288.     DosSleep ((ULONG)Pause);         /* Pause. */
  289.  
  290. }
  291.  
  292. /* ============================= ExchangeSort =================================
  293.  *   The ExchangeSort compares each element in SortArray - starting with
  294.  *   the first element - with every following element.    If any of the
  295.  *   following elements    is smaller than    the current element, it    is exchanged
  296.  *   with the current element and the process is repeated for the next
  297.  *   element in    SortArray.
  298.  * ============================================================================
  299.  */
  300. void ExchangeSort ()
  301. {
  302.     int    Row, SmallestRow, j;
  303.  
  304.     for    (Row = 1; Row <= wMode.row - 1;    Row++) {
  305.     SmallestRow = Row;
  306.     for (j = Row + 1; j <= wMode.row; j++) {
  307.         if (SortArray[j].Length < SortArray[SmallestRow].Length) {
  308.         SmallestRow = j;
  309.         ElapsedTime (j);
  310.         }
  311.     }
  312.        /* Found    a row shorter than the current row, so swap those
  313.     * two array elements: */
  314.     if (SmallestRow    > Row) {
  315.         Swaps (&SortArray[Row], &SortArray[SmallestRow]);
  316.         SwapBars (Row, SmallestRow);
  317.     }
  318.     }
  319.  
  320. }
  321.  
  322. /* =============================== HeapSort ===================================
  323.  *  The    HeapSort procedure works by calling two    other procedures - PercolateUp
  324.  *  and    PercolateDown.    PercolateUp turns SortArray into a "heap," which has
  325.  *  the    properties outlined in the diagram below:
  326.  *
  327.  *                 SortArray[1]
  328.  *                 /        \
  329.  *              SortArray[2]         SortArray[3]
  330.  *             /        \         /        \
  331.  *       SortArray[4]      SortArray[5]     SortArray[6]  SortArray[7]
  332.  *        /       \       /       \       /      \     /    \
  333.  *      ...       ...     ...       ...     ...      ...  ...    ...
  334.  *
  335.  *
  336.  *  where each "parent node" is    greater    than each of its "child nodes";    for
  337.  *  example, SortArray[1] is greater than SortArray[2] or SortArray[3],
  338.  *  SortArray[4] is greater than SortArray[5] or SortArray[6], and so forth.
  339.  *
  340.  *  Therefore, once the    first FOR...NEXT loop in HeapSort is finished, the
  341.  *  largest element is in SortArray[1].
  342.  *
  343.  *  The    second FOR...NEXT loop in HeapSort swaps the element in    SortArray[1]
  344.  *  with the element in    MaxRow,    rebuilds the heap (with    PercolateDown) for
  345.  *  MaxRow - 1,    then swaps the element in SortArray[1] with the    element    in
  346.  *  MaxRow - 1,    rebuilds the heap for MaxRow - 2, and continues    in this    way
  347.  *  until the array is sorted.
  348.  * ============================================================================
  349.  */
  350. void HeapSort ()
  351. {
  352.     int    i;
  353.  
  354.     for    (i = 2;    i <= wMode.row;    i++)
  355.     PercolateUp (i);
  356.  
  357.     for    (i = wMode.row;    i >= 2;    i--) {
  358.     Swaps (&SortArray[1], &SortArray[i]);
  359.     SwapBars (1, i);
  360.     PercolateDown (i - 1);
  361.     }
  362. }
  363.  
  364. /* ============================== Initialize ==================================
  365.  *    Initializes the SortBackup and OptionTitle arrays.  It also calls    the
  366.  *    BoxInit procedure.
  367.  * ============================================================================
  368.  */
  369. void Initialize    ()
  370. {
  371.     int    TempArray[44], i, MaxColors, MaxIndex, Index, BarLength;
  372.  
  373.     for    (i = 1;    i <= wMode.row;    i++)
  374.     TempArray[i] = i;
  375.  
  376.     MaxIndex = wMode.row;
  377.  
  378.     srand (time(0L));         /*    Seed the random-number generator. */
  379.  
  380.     /* If monochrome or    color burst disabled, use one color */
  381.     if ((wMode.fbType &    VGMT_OTHER) && (!(wMode.fbType & VGMT_DISABLEBURST)))
  382.     MaxColors = 15;
  383.     else
  384.     MaxColors = 1;
  385.  
  386.     for    (i = 1;    i <= wMode.row;    i++) {
  387.  
  388.        /* Find a random    element    in TempArray between 1 and MaxIndex,
  389.     * then assign the value    in that    element    to BarLength: */
  390.     Index =    RandInt    (1, MaxIndex);
  391.     BarLength = TempArray[Index];
  392.  
  393.        /* Overwrite the    value in TempArray[Index] with the value in
  394.     * TempArray[MaxIndex] so the value in TempArray[Index] is
  395.     * chosen only once: */
  396.     TempArray[Index] = TempArray[MaxIndex];
  397.  
  398.        /* Decrease the value of    MaxIndex so that TempArray[MaxIndex] can't
  399.     * be chosen on the next    pass through the loop: */
  400.     --MaxIndex;
  401.  
  402.     SortBackup[i].Length = BarLength;
  403.  
  404.     if (MaxColors == 1)
  405.         SortBackup[i].ColorVal = 7;
  406.     else
  407.         SortBackup[i].ColorVal = BarLength % MaxColors + 1;
  408.     }
  409.  
  410.     Cls    ();
  411.     Reinitialize ();     /* Assign values in SortBackup    to SortArray and draw
  412.               * unsorted bars on the screen. */
  413.     Sound = TRUE;
  414.     Pause = 30;         /* Initialize Pause. */
  415.     BoxInit ();         /* Draw frame for the sort menu and print options. */
  416.  
  417. }
  418.  
  419. /* ============================= InsertionSort ================================
  420.  *   The InsertionSort procedure compares the length of    each successive
  421.  *   element in    SortArray with the lengths of all the preceding    elements.
  422.  *   When the procedure    finds the appropriate place for    the new    element, it
  423.  *   inserts the element in its    new place, and moves all the other elements
  424.  *   down one place.
  425.  * ============================================================================
  426.  */
  427. void InsertionSort ()
  428. {
  429.     struct SortType TempVal;
  430.     int    TempLength;
  431.     int    j, Row;
  432.  
  433.     for    (Row = 2; Row <= wMode.row; Row++) {
  434.     TempVal    = SortArray[Row];
  435.     TempLength = TempVal.Length;
  436.     for (j = Row; j    >= 2; j--) {
  437.  
  438.        /* As long as the length of the j-1st element is greater than the
  439.         * length of    the original element in    SortArray[Row],    keep shifting
  440.         * the array    elements down: */
  441.         if (SortArray[j - 1].Length    > TempLength) {
  442.         SortArray[j] = SortArray[j - 1];
  443.         PrintOneBar (j);        /* Print the new bar. */
  444.         ElapsedTime (j);        /* Print the elapsed time. */
  445.  
  446.          /*    Otherwise, exit: */
  447.          } else
  448.         break;
  449.     }
  450.  
  451.     /* Insert the original value of    SortArray[Row] in SortArray[j]:    */
  452.     SortArray[j] = TempVal;
  453.     PrintOneBar (j);
  454.     ElapsedTime (j);
  455.     }
  456. }
  457.  
  458. /* ============================    PercolateDown =================================
  459.  *   The PercolateDown procedure restores the elements of SortArray from 1 to
  460.  *   MaxLevel to a "heap" (see the diagram with    the HeapSort procedure).
  461.  * ============================================================================
  462.  */
  463. void PercolateDown (int    MaxLevel)
  464. {
  465.     int    Child, i = 1;
  466.  
  467.    /* Move the value in    SortArray[0] down the heap until it has    reached
  468.     * its proper node (that is,    until it is less than its parent node
  469.     * or until it has reached MaxLevel,    the bottom of the current heap): */
  470.     for    (;;) {
  471.     Child =    2 * i;          /* Get the subscript for the child node. */
  472.  
  473.     /* Reached the bottom of the heap, so exit this    procedure: */
  474.     if (Child > MaxLevel)
  475.         break;
  476.  
  477.     /* If there are    two child nodes, find out which    one is bigger: */
  478.     if (Child + 1 <= MaxLevel)
  479.         if (SortArray[Child    + 1].Length > SortArray[Child].Length)
  480.         ++Child;
  481.  
  482.        /* Move the value down if it is still not bigger    than either one    of
  483.     * its children:    */
  484.     if (SortArray[i].Length    < SortArray[Child].Length) {
  485.         Swaps (&SortArray[i], &SortArray[Child]);
  486.         SwapBars (i, Child);
  487.         i =    Child;
  488.  
  489.        /* Otherwise, SortArray has been    restored to a heap from    1 to
  490.     * MaxLevel, so exit: */
  491.     } else
  492.         break;
  493.     }
  494. }
  495.  
  496. /* ============================== PercolateUp =================================
  497.  *   The PercolateUp procedure converts    the elements from 1 to MaxLevel    in
  498.  *   SortArray into a "heap" (see the diagram with the HeapSort    procedure).
  499.  * ============================================================================
  500.  */
  501. void PercolateUp (int MaxLevel)
  502. {
  503.     int    i = MaxLevel, Parent;
  504.  
  505.    /* Move the value in    SortArray[MaxLevel] up the heap    until it has
  506.     * reached its proper node (that is,    until it is greater than either
  507.     * of its child nodes, or until it has reached 1, the top of    the heap): */
  508.     while (i !=    1) {
  509.     Parent = i / 2;          /* Get the subscript for the parent node. */
  510.  
  511.        /* The value at the current node    is still bigger    than the value at
  512.     * its parent node, so swap these two array elements: */
  513.     if (SortArray[i].Length    > SortArray[Parent].Length) {
  514.         Swaps (&SortArray[Parent], &SortArray[i]);
  515.         SwapBars (Parent, i);
  516.         i =    Parent;
  517.  
  518.        /* Otherwise, the element has reached its proper    place in the heap,
  519.     * so exit this procedure: */
  520.     } else
  521.         break;
  522.     }
  523. }
  524.  
  525. /* ============================== PrintOneBar =================================
  526.  *  Prints SortArray[Row].BarString at the row indicated by the    Row
  527.  *  parameter, using the color in SortArray[Row].ColorVal.
  528.  * ============================================================================
  529.  */
  530. void PrintOneBar (int Row)
  531. {
  532.     struct CELLINFO Cell;
  533.     int    NumSpaces;
  534.  
  535.     Cell.Attr =    SortArray[Row].ColorVal;
  536.     Cell.Char =    BLOCK;
  537.     VioWrtNCell    ((PBYTE)&Cell, SortArray[Row].Length, Row, 1, 0);
  538.     Cell.Char =    SPACECELL;
  539.     NumSpaces =    wMode.row - SortArray[Row].Length;
  540.     if (NumSpaces > 0)
  541.     VioWrtNCell ((PBYTE)&Cell, NumSpaces, Row, SortArray[Row].Length+1, 0);
  542. }
  543.  
  544. /* ============================== QuickSort ===================================
  545.  *   QuickSort works by    picking    a random "pivot" element in SortArray, then
  546.  *   moving every element that is bigger to one    side of    the pivot, and every
  547.  *   element that is smaller to    the other side.     QuickSort is then called
  548.  *   recursively with the two subdivisions created by the pivot.  Once the
  549.  *   number of elements    in a subdivision reaches two, the recursive calls end
  550.  *   and the array is sorted.
  551.  * ============================================================================
  552.  */
  553. void QuickSort (int Low, int High)
  554. {
  555.     int    i, j, RandIndex, Partition;
  556.  
  557.     if (Low < High) {
  558.  
  559.        /* Only two elements in this subdivision; swap them if they are out of
  560.     * order, then end recursive calls: */
  561.     if (High - Low == 1) {
  562.         if (SortArray[Low].Length >    SortArray[High].Length)    {
  563.         Swaps (&SortArray[Low],    &SortArray[High]);
  564.         SwapBars (Low, High);
  565.         }
  566.     } else {
  567.         Partition =    SortArray[High].Length;
  568.         do {
  569.  
  570.            /* Move in from both sides towards the pivot element: */
  571.         i = Low;
  572.         j = High;
  573.         while ((i < j) && (SortArray[i].Length <= Partition))
  574.             i++;
  575.  
  576.         while ((j > i) && (SortArray[j].Length >= Partition))
  577.             j--;
  578.  
  579.            /* If we    haven't reached the pivot element, it means that two
  580.         * elements on either side are out of order, so swap them: */
  581.         if (i <    j) {
  582.             Swaps (&SortArray[i], &SortArray[j]);
  583.             SwapBars (i, j);
  584.         }
  585.         } while (i < j);
  586.  
  587.        /* Move the pivot element back to its proper    place in the array: */
  588.         Swaps (&SortArray[i], &SortArray[High]);
  589.         SwapBars (i, High);
  590.  
  591.        /* Recursively call the QuickSort procedure (pass the smaller
  592.         * subdivision first    to use less stack space): */
  593.         if ((i - Low) < (High - i))    {
  594.         QuickSort (Low,    i - 1);
  595.         QuickSort (i + 1, High);
  596.         } else {
  597.         QuickSort (i + 1, High);
  598.         QuickSort (Low,    i - 1);
  599.         }
  600.     }
  601.     }
  602. }
  603.  
  604. /* =============================== RandInt ====================================
  605.  *   Returns a random integer greater than or equal to the Lower parameter
  606.  *   and less than or equal to the Upper parameter.
  607.  * ============================================================================
  608.  */
  609. int RandInt (int Lower,    int Upper)
  610. {
  611.     return ((int)((float)rand () / 32767. * (Upper - Lower + 1)) + Lower);
  612. }
  613.  
  614. /* ============================== Reinitialize ================================
  615.  *   Restores the array    SortArray to its original unsorted state, then
  616.  *   prints the    unsorted color bars.
  617.  * ============================================================================
  618.  */
  619. void Reinitialize ()
  620. {
  621.     int    Row;
  622.  
  623.     DosGetDateTime (&sTime);
  624.     oTime = (sTime.hours * 360000) +
  625.         (sTime.minutes * 6000) +
  626.         (sTime.seconds * 100) +
  627.          sTime.hundredths;
  628.  
  629.     for    (Row = 1; Row <= wMode.row; Row++) {
  630.     SortArray[Row] = SortBackup[Row];
  631.     PrintOneBar (Row);
  632.     }
  633. }
  634.  
  635. int Screen (int    ACTION)
  636. {
  637.     static VIOMODEINFO Mode;
  638.     static PCH CellStr;
  639.     static USHORT Row, Col, Length;
  640.     if (ACTION)    {
  641.     Mode.cb    = sizeof(Mode);
  642.     VioGetMode (&Mode, 0);
  643.     Length = 2*Mode.row*Mode.col;
  644.     CellStr    = malloc (Length);
  645.     if (CellStr == NULL)
  646.         return (FALSE);
  647.     VioReadCellStr (CellStr, &Length, 0, 0,    0);
  648.     VioGetCurPos (&Row, &Col, 0);
  649.     }
  650.     else {
  651.     VioSetMode (&Mode, 0);
  652.     if (CellStr == NULL)
  653.         return (FALSE);
  654.     VioWrtCellStr (CellStr,    Length,    0, 0, 0);
  655.     VioSetCurPos (Row, Col,    0);
  656.     }
  657.     return (TRUE);
  658. }
  659.  
  660. /* =============================== ShellSort ==================================
  661.  *  The    ShellSort procedure is similar to the BubbleSort procedure.  However,
  662.  *  ShellSort begins by    comparing elements that    are far    apart (separated by
  663.  *  the    value of the Offset variable, which is initially half the distance
  664.  *  between the    first and last element), then comparing    elements that are
  665.  *  closer together (when Offset is one, the last iteration of this procedure
  666.  *  is merely a    bubble sort).
  667.  * ============================================================================
  668.  */
  669. void ShellSort ()
  670. {
  671.     int    Offset,    Switch,    Limit, Row;
  672.  
  673.     /* Set comparison offset to    half the number    of records in SortArray: */
  674.     Offset = wMode.row / 2;
  675.  
  676.     while (Offset) {         /* Loop until offset gets to zero. */
  677.     Limit =    wMode.row - Offset;
  678.     do {
  679.         Switch = FALSE;       /* Assume no    switches at this offset. */
  680.  
  681.        /* Compare elements and switch ones out of order: */
  682.         for    (Row = 1; Row <= Limit;    Row++)
  683.         if (SortArray[Row].Length > SortArray[Row + Offset].Length) {
  684.             Swaps (&SortArray[Row], &SortArray[Row + Offset]);
  685.             SwapBars (Row, Row + Offset);
  686.             Switch = Row;
  687.         }
  688.  
  689.         /* Sort on next pass only to where last switch was made: */
  690.         Limit = Switch - Offset;
  691.     } while    (Switch);
  692.  
  693.        /* No switches at last offset, try one half as big: */
  694.     Offset = Offset    / 2;
  695.     }
  696. }
  697.  
  698. /* =============================== SortMenu ===================================
  699.  *   The SortMenu procedure first calls    the Reinitialize procedure to make
  700.  *   sure the SortArray    is in its unsorted form, then prompts the user to
  701.  *   make one of the following choices:
  702.  *
  703.  *         * One of the sorting algorithms
  704.  *         * Toggle sound    on or off
  705.  *         * Increase or decrease    speed
  706.  *         * End the program
  707.  * ============================================================================
  708.  */
  709. void SortMenu ()
  710. {
  711.     for    (;;) {
  712.  
  713.     VioSetCurPos (FIRSTMENU    + Nlines - 1, LEFTCOLUMN + 27, 0);
  714.  
  715.     KbdCharIn (&inChar, 0, 0);
  716.  
  717.     /* Branch to the appropriate procedure depending on the    key typed: */
  718.     switch (toupper    (inChar.chChar)) {
  719.         case 'I':
  720.         curSelect = 0;
  721.         Reinitialize ();
  722.         InsertionSort ();
  723.         ElapsedTime (0);          /* Print final time. */
  724.         break;
  725.         case 'B':
  726.         curSelect = 1;
  727.         Reinitialize ();
  728.         BubbleSort ();
  729.         ElapsedTime (0);          /* Print final time. */
  730.         break;
  731.         case 'H':
  732.         curSelect = 2;
  733.         Reinitialize ();
  734.         HeapSort ();
  735.         ElapsedTime (0);          /* Print final time. */
  736.         break;
  737.         case 'E':
  738.         curSelect = 3;
  739.         Reinitialize ();
  740.         ExchangeSort ();
  741.         ElapsedTime (0);          /* Print final time. */
  742.         break;
  743.         case 'S':
  744.         curSelect = 4;
  745.         Reinitialize ();
  746.         ShellSort ();
  747.         ElapsedTime (0);          /* Print final time. */
  748.         break;
  749.         case 'Q':
  750.         curSelect = 5;
  751.         Reinitialize ();
  752.         QuickSort (1, wMode.row);
  753.         ElapsedTime (0);          /* Print final time. */
  754.         break;
  755.         case '>':
  756.  
  757.        /* Decrease pause length to speed up    sorting    time, then redraw
  758.         * the menu to clear    any timing results (since they won't compare
  759.         * with future results): */
  760.         if (Pause != 0)
  761.             Pause -= 30;
  762.         BoxInit    ();
  763.         break;
  764.  
  765.         case '<':
  766.  
  767.        /* Increase pause length to slow down sorting time, then redraw
  768.         * the menu to clear    any timing results (since they won't compare
  769.         * with future results): */
  770.         if (Pause != 900)
  771.             Pause += 30;
  772.         BoxInit    ();
  773.         break;
  774.  
  775.         case 'T':
  776.         Sound =    !Sound;
  777.         BoxInit    ();
  778.         break;
  779.  
  780.         case 27:
  781.  
  782.        /* User pressed ESC,    so exit    this procedure and return to main: */
  783.         return;
  784.     }
  785.     }
  786. }
  787.  
  788. /* =============================== SwapBars ===================================
  789.  *   Calls PrintOneBar twice to    switch the two bars in Row1 and    Row2,
  790.  *   then calls    the ElapsedTime    procedure.
  791.  * ============================================================================
  792.  */
  793. void SwapBars (int Row1, int Row2)
  794. {
  795.     PrintOneBar    (Row1);
  796.     PrintOneBar    (Row2);
  797.     ElapsedTime    (Row1);
  798. }
  799.  
  800. void Cls ()
  801. {
  802.     char Cell =    SPACECELL;
  803.  
  804.     VioScrollDn    (0, 0, -1, -1, -1, &Cell, 0);
  805. }
  806.  
  807. void Swaps (struct SortType *one, struct SortType *two)
  808. {
  809.     struct SortType temp;
  810.  
  811.     temp = *one;
  812.     *one = *two;
  813.     *two = temp;
  814.  
  815. }
  816.