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 ggrotz@2sprint.net