home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c034 / 4.ddi / SOURCE / SORTDEMO.C$ / SORTDEMO.bin
Encoding:
Text File  |  1989-12-14  |  24.1 KB  |  835 lines

  1. /* SORTDEMO -This program graphically demonstrates six common sorting
  2.  * algorithms. It prints 25 or 43 horizontal bars of different lengths
  3.  * in random order, then sorts the bars from shortest to longest.
  4.  * The program can beep to generate different pitches, depending on the
  5.  * length and position of the bar.
  6.  *
  7.  * The program can be created for DOS or OS/2. To create for OS/2, define
  8.  * the symbol OS2. Command lines for DOS and OS/2 are shown below:
  9.  *
  10.  * DOS:
  11.  *    cl /Lr sortdemo.c graphics.lib
  12.  *
  13.  * OS/2:
  14.  *    cl /Lp /DOS2 sortdemo.c grtextp.lib
  15.  */
  16.  
  17. #include <graph.h>          // _outtext, _settextcolor, _settextposition
  18. #include <string.h>         // strlen
  19. #include <stdio.h>          // sprintf
  20. #include <conio.h>          // getch
  21. #include <stdlib.h>         // srand, rand, toupper
  22. #include <malloc.h>         // malloc, free
  23. #include <time.h>           // time, clock
  24.  
  25. enum BOOL { FALSE, TRUE };
  26.  
  27. /* Structure type for colored bars */
  28. typedef struct _BAR
  29. {
  30.     char len;
  31.     char clr;
  32. } BAR;
  33.  
  34. /* Structure type for screen cells */
  35. typedef struct _CELL
  36. {
  37.     char chChar;
  38.     char chAttr;
  39. } CELL;
  40.  
  41. /* Function prototypes */
  42. void main( void  );
  43. void Cls( void  );
  44. void InitMenu( void  );             // Menu Functions
  45. void DrawFrame( int iTop, int Left, int Width, int Height );
  46. void RunMenu( void  );
  47. void DrawTime( int iCurrentRow );
  48. void InitBars( void  );             // Bar functions
  49. void ReInitBars( void  );
  50. void DrawBar( int iRow );
  51. void SwapBars( int iRow1, int iRow2 );
  52. void Swaps( BAR *one, BAR *two );
  53. void InsertionSort( void  );        // Sort functions
  54. void BubbleSort( void  );
  55. void HeapSort( void  );
  56. void PercolateUp( int iMaxLevel );
  57. void PercolateDown( int iMaxLevel );
  58. void ExchangeSort( void  );
  59. void ShellSort( void  );
  60. void QuickSort( int iLow, int iHigh );
  61. void Beep( int frequency, int duration );
  62. void Sleep( clock_t wait );
  63.  
  64. /* Macro */
  65. #define GetRandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))
  66. #define _outtextxy( ach, x, y )   { _settextposition( y, x ); \
  67.                                     _outtext( ach ); }
  68.  
  69. /* Constants */
  70. #define ESC        27
  71. #define BLANK      32
  72. #define BLOCK      223
  73. #define TOP        1
  74. #define FIRSTMENU  (TOP + 6)
  75. #define LEFTCOLUMN 48
  76. #define PROMPTPOS  27
  77. #define WIDTH      (80 - LEFTCOLUMN)
  78. #define HEIGHT     (cszMenu + 2)
  79. #define MENUCOLOR  15
  80. #define BLANKCOLOR 7
  81. #define BACKCOLOR  0L
  82. #define PAUSELIMIT 900
  83.  
  84. /* Global variables */
  85. clock_t clStart, clFinish, clPause = 30L;
  86. int fSound, iCurChoice, iSwaps, iCompares, cRow;
  87.  
  88. BAR abarWork[43], abarPerm[43]; // Temporary and permanent sort arrays
  89.  
  90. char *aszMenu[] =
  91. {
  92.     "",
  93.     "       C Sorting Demo",
  94.     "",
  95.     "              Time  Swap  Comp",
  96.     "",
  97.     "Insertion",
  98.     "Bubble",
  99.     "Heap",
  100.     "Exchange",
  101.     "Shell",
  102.     "Quick",
  103.     "",
  104.     "Toggle Sound: ",
  105.     "",
  106.     "Pause Factor: ",
  107.     "<   (Slower)",
  108.     ">   (Faster)",
  109.     "",
  110.     "Type first character of",
  111.     "choice ( I B H E S Q T < > )",
  112.     "or ESC key to end program: "
  113.     "",
  114. };
  115. int cszMenu = sizeof( aszMenu ) / sizeof( aszMenu[0] );
  116.  
  117. void main()
  118. {
  119.     cRow = _settextrows( 43 );
  120.     _clearscreen( _GCLEARSCREEN );
  121.     _displaycursor( _GCURSOROFF );
  122.     InitBars();
  123.     InitMenu();
  124.     RunMenu();                     // Respond to menu until quit
  125.     _setvideomode( _DEFAULTMODE );
  126. }
  127.  
  128.  
  129. /* InitMenu - Calls the DrawFrame procedure to draw the frame around the
  130.  * sort menu, then prints the different options stored in the menu array.
  131.  */
  132. void InitMenu()
  133. {
  134.     int  i;
  135.     char ach[15];
  136.  
  137.     _settextcolor( MENUCOLOR );
  138.     _setbkcolor( BACKCOLOR );
  139.     DrawFrame( TOP, LEFTCOLUMN - 3, WIDTH + 3, HEIGHT );
  140.     for( i = 0; i < cszMenu; i++ )
  141.         _outtextxy( aszMenu[i], LEFTCOLUMN, TOP + i + 1 );
  142.  
  143.     /* Print the current value for Sound. */
  144.     if( fSound )
  145.         strcpy( ach, "ON " );
  146.     else
  147.         strcpy( ach, "OFF" );
  148.  
  149.     _outtextxy( ach, LEFTCOLUMN + 14, cszMenu - 7 );
  150.     sprintf( ach, "%3.3u", clPause / 30 );
  151.     _outtextxy( ach, LEFTCOLUMN + 14, cszMenu - 5 );
  152.  
  153.     /* Erase the speed option if the length of the pause is at a limit. */
  154.     strcpy( ach, "            " );
  155.     if( clPause == PAUSELIMIT )
  156.         _outtextxy( ach, LEFTCOLUMN, cszMenu - 4 );
  157.     if( clPause == 0L )
  158.         _outtextxy( ach, LEFTCOLUMN, cszMenu - 3 );
  159. }
  160.  
  161.  
  162. /* DrawFrame - Draws a rectangular frame using the double-line box
  163.  * characters. The parameters iTop, iLeft, iWidth, and iHeight are
  164.  * the row and column arguments for the upper-left and lower-right
  165.  * corners of the frame.
  166.  */
  167. void DrawFrame( int iTop, int iLeft, int iWidth, int iHeight )
  168. {
  169.     enum { ULEFT = 201, URIGHT = 187,
  170.            LLEFT = 200, LRIGHT = 188, VERTICAL = 186, HORIZONTAL = 205
  171.          };
  172.     int iRow;
  173.     char achTmp[80];
  174.  
  175.     memset( achTmp, HORIZONTAL, iWidth );
  176.     achTmp[0] = ULEFT;
  177.     achTmp[iWidth - 1] = URIGHT;
  178.     achTmp[iWidth] = '\0';
  179.     _outtextxy( achTmp, iLeft, iTop );
  180.  
  181.     memset( achTmp, BLANK, iWidth );
  182.     achTmp[0] = VERTICAL;
  183.     achTmp[iWidth - 1] = VERTICAL;
  184.     for(  iRow = iTop + 1; iRow <= iHeight; iRow++ )
  185.         _outtextxy( achTmp, iLeft, iRow );
  186.  
  187.     memset( achTmp, HORIZONTAL, iWidth );
  188.     achTmp[0] = LLEFT;
  189.     achTmp[iWidth - 1] = LRIGHT;
  190.     _outtextxy( achTmp, iLeft, iTop + iHeight );
  191. }
  192.  
  193.  
  194. /* RunMenu - The RunMenu procedure first calls the ReInitBars
  195.  * procedure to make sure the abarWork is in its unsorted form, then
  196.  * prompts the user to make one of the following choices:
  197.  *
  198.  *  - Run one of the sorting algorithms
  199.  *  - Toggle sound on or off
  200.  *  - Increase or decrease speed
  201.  *  - End the program
  202.  */
  203. void RunMenu()
  204. {
  205.     char    ch;
  206.  
  207.     while( TRUE )
  208.     {
  209.         iSwaps = iCompares = 0;
  210.         _settextposition( TOP + cszMenu, LEFTCOLUMN + PROMPTPOS );
  211.         _displaycursor( _GCURSORON );
  212.         ch = getch();
  213.         _displaycursor( _GCURSOROFF );
  214.  
  215.         /* Branch to the appropriate procedure depending on the key. */
  216.         switch( toupper( ch ) )
  217.         {
  218.             case 'I':
  219.                 iCurChoice = 0;
  220.                 ReInitBars();
  221.                 InsertionSort();
  222.                 DrawTime( 0 );   // Print final time
  223.                 break;
  224.             case 'B':
  225.                 iCurChoice = 1;
  226.                 ReInitBars();
  227.                 BubbleSort();
  228.                 DrawTime( 0 );
  229.                 break;
  230.  
  231.             case 'H':
  232.                 iCurChoice = 2;
  233.                 ReInitBars();
  234.                 HeapSort();
  235.                 DrawTime( 0 );
  236.                 break;
  237.  
  238.             case 'E':
  239.                 iCurChoice = 3;
  240.                 ReInitBars();
  241.                 ExchangeSort();
  242.                 DrawTime( 0 );
  243.                 break;
  244.  
  245.             case 'S':
  246.                 iCurChoice = 4;
  247.                 ReInitBars();
  248.                 ShellSort();
  249.                 DrawTime( 0 );
  250.                 break;
  251.  
  252.             case 'Q':
  253.                 iCurChoice = 5;
  254.                 ReInitBars();
  255.                 QuickSort( 0, cRow );
  256.                 DrawTime( 0 );
  257.                 break;
  258.  
  259.             case '>':
  260.                 /* Decrease pause length to speed up sorting time, then
  261.                  * redraw the menu to clear any timing results (since
  262.                  * they won't compare with future results).
  263.                  */
  264.                 if( clPause )
  265.                     clPause -= 30L;
  266.                 InitMenu();
  267.                 break;
  268.  
  269.             case '<':
  270.                 /* Increase pause length to slow down sorting time. */
  271.                 if( clPause <= 900L )
  272.                     clPause += 30L;
  273.                 InitMenu();
  274.                 break;
  275.  
  276.             case 'T':
  277.                 fSound = !fSound;
  278.                 InitMenu();
  279.                 break;
  280.  
  281.             case ESC:
  282.                 return;
  283.  
  284.             default:        // Unknown key ignored
  285.                 break;
  286.         }
  287.     }
  288. }
  289.  
  290.  
  291. /* DrawTime - Prints seconds elapsed since the given sorting routine
  292.  * started. Note that this time includes both the time it takes to redraw
  293.  * the bars plus the pause while Beep plays a note, and thus is not an
  294.  * accurate indication of sorting speed.
  295.  */
  296. void DrawTime( int iCurrentRow )
  297. {
  298.     char achTiming[80];
  299.  
  300.     _settextcolor( MENUCOLOR );
  301.     clFinish = clock();
  302.  
  303.     sprintf( achTiming, "%7.2f  %4.i  %4.i",
  304.              (float)(clFinish - clStart) / CLOCKS_PER_SEC,
  305.              iSwaps, iCompares );
  306.  
  307.     /* Print the number of seconds elapsed */
  308.     _outtextxy( achTiming, LEFTCOLUMN + 11, FIRSTMENU + iCurChoice );
  309.     if( fSound )
  310.     {
  311.         Beep( 60 * iCurrentRow, 75 );   // Play note
  312.         Sleep( clPause - 75L );         // Pause adjusted for note duration
  313.     }
  314.     else
  315.         Sleep( clPause );               // Pause
  316. }
  317.  
  318.  
  319. /* InitBars - Initializes the bar arrays and the menu box.
  320.  */
  321. void InitBars()
  322. {
  323.     struct videoconfig vc;
  324.     int aTemp[43], iRow, iRowMax, iRand, iColorMax, iLength;
  325.  
  326.     /* Seed the random-number generator. */
  327.     srand( (unsigned)time( NULL ) );
  328.     fSound = TRUE;
  329.     clPause = 30L;
  330.  
  331.     /* If monochrome or color burst disabled, use one color */
  332.     _getvideoconfig( &vc );
  333.     if( (vc.monitor == _MONO) || (vc.mode == _TEXTBW80) ||
  334.                                  (vc.mode == _TEXTBW40) )
  335.         iColorMax = 1;
  336.     else
  337.         iColorMax = 15;
  338.  
  339.     /* Randomize an array of rows. */
  340.     for( iRow = 0; iRow < cRow; iRow++ )
  341.         aTemp[iRow] = iRow + 1;
  342.     iRowMax = cRow - 1;
  343.     for( iRow = 0; iRow < cRow; iRow++ )
  344.     {
  345.         /* Find a random element in aTemp between 0 and iRowMax,
  346.          * then assign the value in that element to iLength.
  347.          */
  348.         iRand = GetRandom( 0, iRowMax );
  349.         iLength = aTemp[iRand];
  350.  
  351.         /* Overwrite the value in aTemp[iRand] with the value in
  352.          * aTemp[iRowMax] so the value in aTemp[iRand] is
  353.          * chosen only once.
  354.          */
  355.         aTemp[iRand] = aTemp[iRowMax];
  356.  
  357.         /* Decrease the value of iRowMax so that aTemp[iRowMax] can't
  358.          * be chosen on the next pass through the loop.
  359.          */
  360.         --iRowMax;
  361.         abarPerm[iRow].len = iLength;
  362.         if( iColorMax == 1 )
  363.             abarPerm[iRow].clr = BLANKCOLOR;
  364.         else
  365.             abarPerm[iRow].clr = iLength % iColorMax + 1;
  366.     }
  367.  
  368.     /* Assign permanent sort values to temporary and draw unsorted bars. */
  369.     ReInitBars();
  370. }
  371.  
  372.  
  373. /* ReInitBars - Restores the array abarWork to its original unsorted
  374.  * state and draws the unsorted bars.
  375.  */
  376. void ReInitBars()
  377. {
  378.     int iRow;
  379.  
  380.     clStart = clock();
  381.     for( iRow = 0; iRow < cRow; iRow++ )
  382.     {
  383.         abarWork[iRow] = abarPerm[iRow];
  384.         DrawBar( iRow );
  385.     }
  386. }
  387.  
  388.  
  389. /* DrawBar - Prints a bar at a specified row by first blanking the
  390.  * old bar, then drawing a new bar having the length and color given in
  391.  * the work array.
  392.  */
  393. void DrawBar( int iRow )
  394. {
  395.     int  cSpace;
  396.     char achT[43];
  397.  
  398.     memset( achT, BLOCK, abarWork[iRow].len );
  399.     cSpace = cRow - abarWork[iRow].len;
  400.     memset( achT + abarWork[iRow].len, ' ', cSpace );
  401.     achT[cRow] = '\0';
  402.     _settextcolor( abarWork[iRow].clr );
  403.     _outtextxy( achT, 0, iRow + 1 );
  404. }
  405.  
  406.  
  407. /* SwapBars - Calls DrawBar twice to switch the two bars in iRow1 and
  408.  * iRow2, then calls DrawTime to update the time.
  409.  */
  410. void SwapBars( int iRow1, int iRow2 )
  411. {
  412.     DrawBar( iRow1 );
  413.     DrawBar( iRow2 );
  414.     DrawTime( iRow1 );
  415. }
  416.  
  417.  
  418. /* Swaps - Exchanges two bar structures.
  419.  */
  420. void Swaps( BAR *bar1, BAR *bar2 )
  421. {
  422.     BAR barTmp;
  423.  
  424.     ++iSwaps;
  425.     barTmp = *bar1;
  426.     *bar1  = *bar2;
  427.     *bar2  = barTmp;
  428. }
  429.  
  430.  
  431. /* InsertionSort - InsertionSort compares the length of each element
  432.  * with the lengths of all the preceding elements. When the appropriate
  433.  * place for the new element is found, the element is inserted and
  434.  * all the other elements are moved down one place.
  435.  */
  436. void InsertionSort()
  437. {
  438.     BAR barTemp;
  439.     int iRow, iRowTmp, iLength;
  440.  
  441.     /* Start at the top. */
  442.     for( iRow = 0; iRow < cRow; iRow++ )
  443.     {
  444.         barTemp = abarWork[iRow];
  445.         iLength = barTemp.len;
  446.  
  447.         /* As long as the length of the temporary element is greater than
  448.          * the length of the original, keep shifting the elements down.
  449.          */
  450.         for( iRowTmp = iRow; iRowTmp; iRowTmp-- )
  451.         {
  452.             iCompares++;
  453.             if( abarWork[iRowTmp - 1].len > iLength )
  454.             {
  455.                 ++iSwaps;
  456.                 abarWork[iRowTmp] = abarWork[iRowTmp - 1];
  457.                 DrawBar( iRowTmp );         // Print the new bar
  458.                 DrawTime( iRowTmp );        // Print the elapsed time
  459.  
  460.             }
  461.             else                            // Otherwise, exit
  462.                 break;
  463.         }
  464.  
  465.         /* Insert the original bar in the temporary position. */
  466.         abarWork[iRowTmp] = barTemp;
  467.         DrawBar( iRowTmp );
  468.         DrawTime( iRowTmp );
  469.     }
  470. }
  471.  
  472.  
  473. /* BubbleSort - BubbleSort cycles through the elements, comparing
  474.  * adjacent elements and swapping pairs that are out of order. It
  475.  * continues to do this until no out-of-order pairs are found.
  476.  */
  477. void BubbleSort()
  478. {
  479.     int iRow, iSwitch, iLimit = cRow;
  480.  
  481.     /* Move the longest bar down to the bottom until all are in order. */
  482.     do
  483.     {
  484.         iSwitch = 0;
  485.         for( iRow = 0; iRow < iLimit; iRow++ )
  486.         {
  487.             /* If two adjacent elements are out of order, swap their values
  488.              * and redraw those two bars.
  489.              */
  490.             iCompares++;
  491.             if( abarWork[iRow].len > abarWork[iRow + 1].len )
  492.             {
  493.                 Swaps( &abarWork[iRow], &abarWork[iRow + 1] );
  494.                 SwapBars( iRow, iRow + 1 );
  495.                 iSwitch = iRow;
  496.             }
  497.         }
  498.  
  499.         /* Sort on next pass only to where the last switch was made. */
  500.         iLimit = iSwitch;
  501.     } while( iSwitch );
  502. }
  503.  
  504.  
  505. /* HeapSort - HeapSort (also called TreeSort) works by calling
  506.  * PercolateUp and PercolateDown. PercolateUp organizes the elements
  507.  * into a "heap" or "tree," which has the properties shown below:
  508.  *
  509.  *                             element[1]
  510.  *                           /            \
  511.  *                element[2]                element[3]
  512.  *               /          \              /          \
  513.  *         element[4]     element[5]   element[6]    element[7]
  514.  *         /        \     /        \   /        \    /        \
  515.  *        ...      ...   ...      ... ...      ...  ...      ...
  516.  *
  517.  *
  518.  * Each "parent node" is greater than each of its "child nodes"; for
  519.  * example, element[1] is greater than element[2] or element[3];
  520.  * element[4] is greater than element[5] or element[6], and so forth.
  521.  * Therefore, once the first loop in HeapSort is finished, the
  522.  * largest element is in element[1].
  523.  *
  524.  * The second loop rebuilds the heap (with PercolateDown), but starts
  525.  * at the top and works down, moving the largest elements to the bottom.
  526.  * This has the effect of moving the smallest elements to the top and
  527.  * sorting the heap.
  528.  */
  529. void HeapSort()
  530. {
  531.     int i;
  532.  
  533.     for( i = 1; i < cRow; i++ )
  534.         PercolateUp( i );
  535.  
  536.     for( i = cRow - 1; i > 0; i-- )
  537.     {
  538.         Swaps( &abarWork[0], &abarWork[i] );
  539.         SwapBars( 0, i );
  540.         PercolateDown( i - 1 );
  541.     }
  542. }
  543.  
  544.  
  545. /* PercolateUp - Converts elements into a "heap" with the largest
  546.  * element at the top (see the diagram above).
  547.  */
  548. void PercolateUp( int iMaxLevel )
  549. {
  550.     int i = iMaxLevel, iParent;
  551.  
  552.     /* Move the value in abarWork[iMaxLevel] up the heap until it has
  553.      * reached its proper node (that is, until it is greater than either
  554.      * of its child nodes, or until it has reached 1, the top of the heap).
  555.      */
  556.     while( i )
  557.     {
  558.         iParent = i / 2;    // Get the subscript for the parent node
  559.  
  560.         iCompares++;
  561.         if( abarWork[i].len > abarWork[iParent].len )
  562.         {
  563.             /* The value at the current node is bigger than the value at
  564.              * its parent node, so swap these two array elements.
  565.              */
  566.             Swaps( &abarWork[iParent], &abarWork[i] );
  567.             SwapBars( iParent, i );
  568.             i = iParent;
  569.         }
  570.         else
  571.             /* Otherwise, the element has reached its proper place in the
  572.              * heap, so exit this procedure.
  573.              */
  574.             break;
  575.     }
  576. }
  577.  
  578.  
  579. /* PercolateDown - Converts elements to a "heap" with the largest elements
  580.  * at the bottom. When this is done to a reversed heap (largest elements
  581.  * at top), it has the effect of sorting the elements.
  582.  */
  583. void PercolateDown( int iMaxLevel )
  584. {
  585.     int iChild, i = 0;
  586.  
  587.     /* Move the value in abarWork[0] down the heap until it has reached
  588.      * its proper node (that is, until it is less than its parent node
  589.      * or until it has reached iMaxLevel, the bottom of the current heap).
  590.      */
  591.     while( TRUE )
  592.     {
  593.         /* Get the subscript for the child node. */
  594.         iChild = 2 * i;
  595.  
  596.         /* Reached the bottom of the heap, so exit this procedure. */
  597.         if( iChild > iMaxLevel )
  598.             break;
  599.  
  600.         /* If there are two child nodes, find out which one is bigger. */
  601.         if( iChild + 1 <= iMaxLevel )
  602.         {
  603.             iCompares++;
  604.             if( abarWork[iChild + 1].len > abarWork[iChild].len )
  605.                 iChild++;
  606.         }
  607.  
  608.         iCompares++;
  609.         if( abarWork[i].len < abarWork[iChild].len )
  610.         {
  611.             /* Move the value down since it is still not bigger than
  612.              * either one of its children.
  613.              */
  614.             Swaps( &abarWork[i], &abarWork[iChild] );
  615.             SwapBars( i, iChild );
  616.             i = iChild;
  617.         }
  618.         else
  619.             /* Otherwise, abarWork has been restored to a heap from 1 to
  620.              * iMaxLevel, so exit.
  621.              */
  622.             break;
  623.     }
  624. }
  625.  
  626.  
  627. /* ExchangeSort - The ExchangeSort compares each element--starting with
  628.  * the first--with every following element. If any of the following
  629.  * elements is smaller than the current element, it is exchanged with
  630.  * the current element and the process is repeated for the next element.
  631.  */
  632. void ExchangeSort()
  633. {
  634.     int iRowCur, iRowMin, iRowNext;
  635.  
  636.     for( iRowCur = 0; iRowCur < cRow; iRowCur++ )
  637.     {
  638.         iRowMin = iRowCur;
  639.         for( iRowNext = iRowCur; iRowNext < cRow; iRowNext++ )
  640.         {
  641.             iCompares++;
  642.             if( abarWork[iRowNext].len < abarWork[iRowMin].len )
  643.             {
  644.                 iRowMin = iRowNext;
  645.                 DrawTime( iRowNext );
  646.             }
  647.         }
  648.  
  649.         /* If a row is shorter than the current row, swap those two
  650.          * array elements.
  651.          */
  652.         if( iRowMin > iRowCur )
  653.         {
  654.             Swaps( &abarWork[iRowCur], &abarWork[iRowMin] );
  655.             SwapBars( iRowCur, iRowMin );
  656.         }
  657.     }
  658. }
  659.  
  660.  
  661. /* ShellSort - ShellSort is similar to the BubbleSort. However, it
  662.  * begins by comparing elements that are far apart (separated by the
  663.  * value of the iOffset variable, which is initially half the distance
  664.  * between the first and last element), then comparing elements that
  665.  * are closer together. When iOffset is one, the last iteration of
  666.  * is merely a bubble sort.
  667.  */
  668. void ShellSort()
  669. {
  670.     int iOffset, iSwitch, iLimit, iRow;
  671.  
  672.     /* Set comparison offset to half the number of bars. */
  673.     iOffset = cRow / 2;
  674.  
  675.     while( iOffset )
  676.     {
  677.         /* Loop until offset gets to zero. */
  678.         iLimit = cRow - iOffset;
  679.         do
  680.         {
  681.             iSwitch = FALSE;     // Assume no switches at this offset.
  682.  
  683.             /* Compare elements and switch ones out of order. */
  684.             for( iRow = 0; iRow <= iLimit; iRow++ )
  685.             {
  686.                 iCompares++;
  687.                 if( abarWork[iRow].len > abarWork[iRow + iOffset].len )
  688.                 {
  689.                     Swaps( &abarWork[iRow], &abarWork[iRow + iOffset] );
  690.                     SwapBars( iRow, iRow + iOffset );
  691.                     iSwitch = iRow;
  692.                 }
  693.             }
  694.  
  695.             /* Sort on next pass only to where last switch was made. */
  696.             iLimit = iSwitch - iOffset;
  697.         } while( iSwitch );
  698.  
  699.         /* No switches at last offset, try one half as big. */
  700.         iOffset = iOffset / 2;
  701.     }
  702. }
  703.  
  704.  
  705. /* QuickSort - QuickSort works by picking a random "pivot" element,
  706.  * then moving every element that is bigger to one side of the pivot,
  707.  * and every element that is smaller to the other side. QuickSort is
  708.  * then called recursively with the two subdivisions created by the pivot.
  709.  * Once the number of elements in a subdivision reaches two, the recursive
  710.  * calls end and the array is sorted.
  711.  */
  712. void QuickSort( int iLow, int iHigh )
  713. {
  714.     int iUp, iDown, iBreak;
  715.  
  716.     if( iLow < iHigh )
  717.     {
  718.         /* Only two elements in this subdivision; swap them if they are
  719.          * out of order, then end recursive calls.
  720.          */
  721.         if( (iHigh - iLow) == 1 )
  722.         {
  723.             iCompares++;
  724.             if( abarWork[iLow].len > abarWork[iHigh].len )
  725.             {
  726.                 Swaps( &abarWork[iLow], &abarWork[iHigh] );
  727.                 SwapBars( iLow, iHigh );
  728.             }
  729.         }
  730.         else
  731.         {
  732.             iBreak = abarWork[iHigh].len;
  733.             do
  734.             {
  735.                 /* Move in from both sides towards the pivot element. */
  736.                 iUp = iLow;
  737.                 iDown = iHigh;
  738.                 iCompares++;
  739.                 while( (iUp < iDown) && (abarWork[iUp].len <= iBreak) )
  740.                     iUp++;
  741.                 iCompares++;
  742.                 while( (iDown > iUp) && (abarWork[iDown].len >= iBreak) )
  743.                     iDown--;
  744.                 /* If we haven't reached the pivot, it means that two
  745.                  * elements on either side are out of order, so swap them.
  746.                  */
  747.                 if( iUp < iDown )
  748.                 {
  749.                     Swaps( &abarWork[iUp], &abarWork[iDown] );
  750.                     SwapBars( iUp, iDown );
  751.                 }
  752.             } while ( iUp < iDown );
  753.  
  754.             /* Move pivot element back to its proper place in the array. */
  755.             Swaps( &abarWork[iUp], &abarWork[iHigh] );
  756.             SwapBars( iUp, iHigh );
  757.  
  758.             /* Recursively call the QuickSort procedure (pass the smaller
  759.              * subdivision first to use less stack space).
  760.              */
  761.             if( (iUp - iLow) < (iHigh - iUp) )
  762.             {
  763.                 QuickSort( iLow, iUp - 1 );
  764.                 QuickSort( iUp + 1, iHigh );
  765.             }
  766.             else
  767.             {
  768.                 QuickSort( iUp + 1, iHigh );
  769.                 QuickSort( iLow, iUp - 1 );
  770.             }
  771.         }
  772.     }
  773. }
  774.  
  775. /* Beep - Sounds the speaker for a time specified in microseconds by
  776.  * duration at a pitch specified in hertz by frequency.
  777.  */
  778. void Beep( int frequency, int duration )
  779. {
  780. /* Use system call for OS/2 */
  781. #if defined( OS2 )
  782. #define INCL_NOCOMMON
  783. #define INCL_NOPM
  784. #define INCL_DOSPROCESS
  785. #include <os2.h>
  786.     DosBeep( frequency, duration );
  787. #else
  788. /* Define procedure for DOS */
  789.     int control;
  790.  
  791.     /* If frequency is 0, Beep doesn't try to make a sound. It
  792.      * just sleeps for the duration.
  793.      */
  794.     if( frequency )
  795.     {
  796.         /* 75 is about the shortest reliable duration of a sound. */
  797.         if( duration < 75 )
  798.             duration = 75;
  799.  
  800.         /* Prepare timer by sending 10111100 to port 43. */
  801.         outp( 0x43, 0xb6 );
  802.  
  803.         /* Divide input frequency by timer ticks per second and
  804.          * write (byte by byte) to timer.
  805.          */
  806.         frequency = (unsigned)(1193180L / frequency);
  807.         outp( 0x42, (char)frequency );
  808.         outp( 0x42, (char)(frequency >> 8) );
  809.  
  810.         /* Save speaker control byte. */
  811.         control = inp( 0x61 );
  812.  
  813.         /* Turn on the speaker (with bits 0 and 1). */
  814.         outp( 0x61, control | 0x3 );
  815.     }
  816.  
  817.     Sleep( (clock_t)duration );
  818.  
  819.     /* Turn speaker back on if necessary. */
  820.     if( frequency )
  821.         outp( 0x61, control );
  822.  
  823. #endif              /* DOS version */
  824. }
  825.  
  826. /* Pauses for a specified number of microseconds. */
  827. void Sleep( clock_t wait )
  828. {
  829.     clock_t goal;
  830.  
  831.     goal = wait + clock();
  832.     while( goal >= clock() )
  833.         ;
  834. }
  835.