Beginning Pascal Tutorial Part 15

                       Turbo Pascal for DOS Tutorial
                            by Glenn Grotzinger
                   Part 15: Concepts of Sorting Arrays
                copyright (c) 1995-96 by Glenn Grotzinger

Here is a solution from last time...keep in mind to be as efficient as
possible in coding...I figure that many will try simply writing those
frames out.

program part14; uses crt;

  var
    esccount: byte;
    chr: char;

  procedure setitup;
    begin
      { green border of 4 units }
      textbackground(green);
      clrscr;
      window(5,5, 76, 21);

      { red border of one unit }
      textbackground(red);
      clrscr;
      window(6,6,75,20);

      { set up black background }
      textbackground(black);
      clrscr;

      { write keypress statement }
      highvideo;
      textcolor(lightcyan);
      writeln('Keypress Detector (Press ESC 5 times to quit)');

      { preserve Keypress detector title. }
      window(6,7,75,20);
    end;

  function status(char1: char;var esccount: byte): string;
    var
      char2: char;
    begin
      if char1 = #0 then
        begin
          char2 := readkey;
          case char2 of
            #59: status := 'F1';
            #60: status := 'F2';
            #61: status := 'F3';
            #62: status := 'F4';
            #63: status := 'F5';
            #64: status := 'F6';
            #65: status := 'F7';
            #66: status := 'F8';
            #67: status := 'F9';
            #68: status := 'F10';
            #82: status := 'Insert';
            #71: status := 'Home';
            #73: status := 'PageUp';
            #81: status := 'PageDown';
            #83: status := 'Delete';
            #79: status := 'End';
            #77: status := 'Right';
            #72: status := 'Up';
            #80: status := 'Down';
            #75: status := 'Left';
          end;
        end
      else
        case char1 of
          #8: status := 'Backspace';
          #9: status := 'TAB';
          #13: status := 'ENTER';
          #27: begin
                 status := 'ESC';
                 inc(esccount, 1);
                 { the 1 is not required here, but the inc and dec
                   functions can be used with values greater than
                   one like this in this case }
               end;
          #32: status := 'SPACE';
        else
          status := char1;
        end;
    end;

  procedure endit;
    var
      i: byte;
    begin
      window(1,1,80,25);
      gotoxy(1,1);
      for i := 1 to 25 do
        begin
          delline;
          delay(100);
        end;
    end;

  begin
    esccount := 0;
    setitup;

    while esccount <> 5 do
      begin
        chr := readkey;
        normvideo;
        textcolor(lightblue);
        write('You pressed the ');
        highvideo;
        textcolor(green);
        write(status(chr, esccount));
        normvideo;
        textcolor(lightblue);
        writeln(' key.');
      end;

    endit;
  end.
Now, we will discuss the use of sorting with regards to arrays into a
particular order.  Sometimes we may need numbers, such as dates in
chronological order, or a list of names in alphabetical order.

Swapping Units
==============
The integral part of a sorting routine is a unit swap.  As a rule, we
MUST have a temporary variable, because a simple assign set will not
work.

For example, to swap the contents in variables a and b, we need a
temporary variable we will call temp.  Then code such as what is below
will do...

temp := b;
b := a;
a := temp;

The swap should ideally be performed with the smallest units possible,
based on the sorting key.  The idea of a sorting key will be explained
later.  You may end up using pointers to get it to move the smallest
amount of data, which will be explained in a future part.  The less
amount of data the computer can move, the better.

The BubbleSort (or the brute force sort)
========================================
Basically, in this sorting method, each and every item in the array is
compared each and every other item in the array.  This is a largely
inefficient method for sorting items, but easy to code, and useful for
small amounts of data.

program example_of_bubblesort;

  var
    thearray: array[1..20] of integer;
    temp: integer;
    i, j: integer;

  begin
    randomize;
    { generate numbers for array and write them as unsorted }
    write('The unsorted array: ');
    for i := 1 to 20 do
      begin
        thearray[i] := random(50) + 1;
        write(thearray[i], ' ');
      end;
    writeln;

    { the bubblesort. }
    for i := 1 to 20 do
      for j := i+1 to 20 do
        if thearray[i] > thearray[j] then { compare and swap }
          begin
            temp := thearray[i];
            thearray[i] := thearray[j];
            thearray[j] := temp;
          end;

    write('The sorted array: ');
    for i := 1 to 20 do
      write(thearray[i], ' ');
    writeln;

end.

As it is a purely iterative solution, you should have no exact trouble
seeing what is going on.  But to further another point as to exactly
how it works, and why it is so inefficient, we will sort a sample set
of numbers manually according to this algorithm to see what is going
on.

1       3       2       5       4

We will start out with the following short description of what is
going on within the two for loops for 5 values of data:

1) i = 1; j = 2; Position1 = 1; Position2 = 3; 1 > 3 = false;
2) i = 1; j = 3; Position1 = 1; Position3 = 2; 1 > 2 = false;
3) i = 1; j = 4; Position1 = 1; Position4 = 5; 1 > 5 = false;
4) i = 1; j = 5; Position1 = 1; Position5 = 4; 1 > 4 = false;

5) i = 2; j = 3; Position2 = 3; Position3 = 2; 3 > 2 = true; we swap
the
two values...so our resultant array is...

1       2       3       5       4

6) i = 2; j = 4; Position2 = 2; Position4 = 5; 2 > 5 = false;
7) i = 2; j = 5; Position2 = 2; Position5 = 4; 2 > 4 = false;

8) i = 3; j = 4; Position3 = 3; Position4 = 5; 3 > 5 = false;
9) i = 3; j = 5; Position3 = 3; Position5 = 4; 3 > 4 = false;

10) i = 4; j = 5; Position4 = 5; Position5 = 4; 5 > 4 = true; we swap
the two values...so the resultant array is...

1       2       3       4       5

11) Effective termination of loop;

As we can see, we took 10 steps in the algorithm to swap 2 elements of
the array in order to sort it.  Basically, this is a very inefficient
algorithm in comparison to other types that are available, as we are
considering portions of the array that are already sorted.  As a note,
to sort the items in descending order instead of ascending order,
change the comparison between the two positions i and j of the array
from > to <.

QuickSort
=========
This is a much faster recursive solution for sorting than the
bubblesort. It makes use of a pivot marker, which moves according to
what exactly is contained in the array.  It also will make use of a
"divide and conquer" approach.  Here is a short example...

program example_of_quicksort;

  var
    thearray: array[1..20] of integer;
    i, j, PIVOT, t: integer;

  procedure quicksort(L, R: integer);
    begin
      if L < R then
        begin
          i := L + 1;
          j := R;
          PIVOT := thearray[L];

          repeat
            while thearray[i] <= PIVOT do inc(i);
            while thearray[j] > PIVOT do dec(j);
            if i < j then
              begin
                t := thearray[i];
                thearray[i] := thearray[j];
                thearray[j] := t;
              end;
          until i > j;

          thearray[L] := thearray[j];
          thearray[j] := PIVOT;

          quicksort(L, j-1);
          quicksort(i, R);
        end;
    end;

  begin
    randomize;
    write('The unsorted array is: ');
    for i := 1 to 20 do
      begin
        thearray[i] := random(50) + 1;
        write(thearray[i], ' ');
      end;

    quicksort(1, 20);

    write('The sorted array is: ');
    for i := 1 to 20 do
      write(thearray[i], ' ');
  end.

This is a recursive solution, so it will be a little different.  Let's
start with the same number sequence we had above and see how quicksort
works...keep in mind that quicksort is about as inefficient as bubble-
sort with smaller sets...Once you get into larger sets, quicksort
beats bubblesort hands down -- it more intelligently seeks the proper
array units to swap.

1       3       2       5       4

1) 1 < 5 = true so continue.... i = 2; j = 5; PIVOT = 4;
   3 <= 4 = true so i = 3; 2 <= 4 = true so i = 4;
   5 <= 4 = false so quit;

   4 > 5 so quit;
   4 < 5 = true, so swap values.  The resulting swap is...

1       3       2       4       5

   4 > 5 = false so continue on repeat loop...

   i = 4; j = 5; PIVOT = 4; 4 <= 4 = true so i = 5;
   5 <= 4 = false so quit;

   5 > 4 = true so j = 4; 4 > 4 = false so quit;

   5 > 4 = true so quit repeat loop.

   j = 4; i = 5; 4 is left side. 4th element is 4.

2) Quicksort called for left side of 1, and right side of 3.  Then
quicksort for left side of 5, and right side of 5. Essentially, we
keep cutting the array in half based by where the pivot lands.  We
will process the quicksort for the left side as 2a) and the quicksort
for the right side as 2b).

2a) Our number set for this instance of quicksort is:

1       3       2

    1 < 3 = true so continue.

    i = 2; j = 3; PIVOT = 2; 3 <= 2 = false so quit;
    i = 2; j = 3; PIVOT = 2; 2 > 2 = false so quit;

    2 < 3 = true so swap values...the resulting swap is...

1       2       3

    2 > 3 = false so quit repeat loop.

    Quicksort called twice for left side of 1, 2 and 2,3.  The results

    of both of these sorts end up being false, so they will terminate
    readily.

2b) 5 < 5 = false so terminate quicksort.

As we can see, the algorithm sets itself up so it ignores portions of
the array that are already sorted.  For larger arrays, it will provide
a great performance boost as we are ignoring the parts of the array
that happen to be sorted by using this particular algorithm.

The version of quicksort pictured sorts in ascending order.  To make
it sort in descending order, change the two while loops to read the
following:

while thearray[i] <= PIVOT do inc(i);
while thearray[j] > PIVOT do dec(j);

ShellSort
=========
This is a non-recursive sort that performs close in performance to
quicksort. We can follow what is going on, so I will just simply write
an example of the use of the shellsort, and describe how to change it
to sort in descending order instead of ascending order...

program example_of_shellsort;

  var
    thearray: array[1..20] of integer;
    i: integer;

  procedure shellsort(n: integer);
    const
      m = 3;   { total number of sort passes }
    var
      i: array[1..m] of integer;
      j, k, p, s, t, incr: integer;
    begin
      i[m] := 1;
      for j := m - 1 downto 1 do i[j] := 2 * i[j];
      for j := 1 to m do
        begin
          incr := i[j];
          for k := 1 to incr do
            begin
              s := incr + k;
              while s <= n do
                begin
                  p := s;
                  t := thearray[p];
                  thearray[k-incr] := t;
                  while t < thearray[p-incr] do
                    begin
                      thearray[p] := thearray[p-incr];
                      dec(p, incr);
                    end;
                  thearray[p] := t;
                  inc(s, incr);
                end;
            end;
        end;
    end;

  begin
    randomize;
    write('The unsorted array is: ');
    for i := 1 to 20 do
      begin
        thearray[i] := random(50) + 1;
        write(thearray[i], ' ');
      end;
    writeln;

    shellsort(20);  { 20 is high end of array }

    write('The sorted array is: ');
    for i := 1 to 20 do
      write(thearray[i], ' ');
    writeln;
  end.
To get it to sort in ascending order instead of descending order,
change the line:

while t < a[p-inc] do

to

while t > a[p-inc] do

Practice
========
You should practice using these sorting methods.  They stay basically
as indicated for any use, except for changing the identities of the
item type in the array we sort.  For strings, we can alphabetize them
by using the strings in the sorting routine for ascending order.  Look
at the ASCII chart...It sees characters as numbers... a < b < c ...et
al...  With strings, be sure to sort them case insensitively,
especially, if we alphabetize a list or something like that....

Next Time
=========
We will cover methods of searching an array for data.  send comments
to ggr...@2sprint.net

Glenn Grotzinger
mailto:ggr...@2sprint.net
MOD and S3M user extraordinaire.
Writer of TP tutorial.  All released parts findable at:
ftp://garbo.uwasa.fi/pc/turbopas/tptutr0a.zip