Skip to main content

 "The average woman would rather have beauty than brains  because
the average man can see better than he can think."


                YOUR SECOND GFA BASIC 3.XX MANUAL
                             - or -
        HOW I LEARNED TO STOP WORRYING AND LOVE GFA-BASIC
                             PART 6
                       CHAPTER FIVE - SORT
                          by Han Kempen

QSORT v. SSORT

 QSORT  is faster than SSORT,  unless the array is almost  sorted
already. I understand QSORT uses the recursive Quick-sort method,
so  you need more memory than with SSORT (iterative  Shell-sort).
Sort-freaks  can  try to implement sort-algorithms  like  Bubble-
sort,  Selection-sort,  Quick-sort  and Shell-sort with  ordinary
GFA-Basic  commands.  That  doesn't make much sense  if  you  are
sorting  one-dimensional arrays (as in the  following  examples),
but  you could adapt the following for multi-dimensional  arrays.
For one-dimensional arrays you should stick to the fast QSORT (or
SSORT).  Please note (again) that variable-names without  postfix
are word-variables!

 The most popular sort-algorithm probably is the 'Bubble-sort':

     ' Sort word-array numb()
     FOR i=SUB(DIM?(numb()),2) DOWNTO 1
       FOR j=0 TO i
         IF numb(j)>numb(SUCC(j))
           SWAP numb(j),numb(SUCC(j))
         ENDIF
       NEXT j
     NEXT i

 Very simple to program,  but unfortunately very slow. Unless the
array is almost sorted already.

 Almost  as simple as the Bubble-sort,  but much faster,  is  the
'Combsort':

     ' Sort word-array numb()
     last=DIM?(numb())-1
     gap=last
     DO
       gap=MAX(DIV(MUL(gap,8),11),1)         ! gap*8/11 or 1
       CLR switch
       FOR i=0 TO SUB(last,gap)
         j=ADD(i,gap)
         IF numb(i)>numb(j)
           SWAP numb(i),numb(j)
           INC switch
         ENDIF
       NEXT i
     LOOP UNTIL switch=0 AND gap=1

 Other  sort-algorithms  are  even  faster,  but  are  also  more
complicated.  Consult  your favourite Algorithm-gospel  for  more
information about sorting.

QSORT of number-arrays

 Number-arrays  can  be QSORTed (in increasing  order)  in  three
different ways:

     QSORT x&()          ! sorts array; also with x|(), x%() or
                                                             x#()
     QSORT x&(),n        ! sorts elements 0 through n-1
     QSORT x&(),n,y%()   ! elements of index-array y%() are
                                                      swapped too

 In all cases x&(-1) results in sorting in decreasing order.

 The  third  method (with an index-array) is interesting  if  you
need  a  sorted output,  but don't want to  change  the  original
array. You can accomplish this as follows:

     - copy word-array x&() to temporary array temp&()
     - determine index of last element: last=DIM?(temp&())-1
     - create index array: DIM index%(last)
     - fill index-array with index 0 through last
     - sort temporary array: QSORT temp&(),last+1,index%()
     - ERASE temp&()

 The index-array must be an integer-array (postfix %).  Also, the
number  of  elements is not optional if you sort with  an  index-
array.  You can now print the numbers in the original array  x&()
in  increasing  order and you can also save  the  index-array  on
disk:

     FOR i=0 TO last
       PRINT x&(index%(i))
     NEXT i
     '
     BSAVE "INDEX.DAT",V:index%(0),(last+1)*4

QSORT of string-arrays

 A string-array can be sorted in the same three ways as described
for  number-arrays.  If  you  have created  an  index-array  with
last.name$(), you could print an alphabetical list:

     FOR i=0 TO last
       PRINT first.name$(index%(i))'last.name$(index%(i))
     NEXT i

 It's a better idea to create the index-array with the  temporary
string-array complete.name$():

     complete.name$(i)=last.name$(i)+first.name$(i)

 After  sorting,  'Bert Kempen' will now be printed  before  'Han
Kempen'.  If a string-array contains empty strings, these strings
will fill the first elements of the array after sorting.  Usually
you'll DELETE the empty strings before continuing:

     WHILE txt$(0)=""
       DELETE txt$(0)
     WEND

 After deleting the empty strings, the dimension of the array has
not been changed.  Actually, the empty strings have been moved to
the end of the array.

 There  are two extra possibilities with string-arrays.  For  the
first possibility,  create a byte-array and fill with appropriate
ASCII-values:

     DIM ascii|(255)
     ARRAYFILL ascii|(),32    ! CHR$(32) is the space-character
     FOR i=48 TO 57
       ascii|(i)=i            ! 0 - 9
     NEXT i
     FOR i=65 TO 90
       ascii|(i)=i            ! A - Z
     NEXT i
     FOR i=97 TO 122
       ascii|(i)=SUB(i,32)    ! a - z converted to A - Z
     NEXT i

 All  characters that are not numbers or letters will be  treated
as a space (ASCII-value 32). Use the array ascii|() for sorting a
string-array (the use of an index-array is optional):

     QSORT x$() WITH ascii|() [,n[,y%()]]

 Now  'Atari' and 'ATARI' are treated exactly the  same,  because
the  array  ascii|()  is  used  to  convert  lower  case  letters
temporarily to upper case before sorting.  You can even treat the
special characters (ASCII-values above 127) correctly.  Use a few
DATA-lines to add the correct ASCII-values to the array ascii|(),
like this:

    RESTORE ascii.data
    REPEAT
      READ code1,code2
      ascii|(code1)=code2
    UNTIL code1=0
    '
    ascii.data:
    ' format: ASCII-code,replacement
    DATA 128,67,129,85,130,69,131,65,132,65,133,65,134,65,135,67
    '     Ç >C   ü >U   é >E   â >A   ä >A   à >A   å >A   ç >A
    DATA 136,69,137,69,138,69,139,73,140,73,141,73,142,65,143,65
    '     ê >E   ë >E   è >E   ï >I   î >I   ì >I   Ä >A   Å >A
    DATA 144,69,145,65,146,65,147,79,148,79,149,79,150,85,151,85
    '     É >E   æ >A   Æ >A   ô >O   ö >O   ò >O   û >U   ù >U
    DATA 152,121,153,79,154,85,155,67,158,83,160,65,161,73,162,79
    '     ÿ >Y    Ö >O   Ü >U   ¢ >C   ß >S   á >A   í >I   ó >O
    DATA 163,85,164,78,165,78,166,65,167,79,176,65,177,79,178,79
    '     ú >U   ñ >N   Ñ >N   ª >A   º >O   ã >A   õ >O   Ø >O
    DATA 179,79,180,79,181,79,182,65,183,65,184,79,192,121,193,121
    '     ø >O   œ >O   Œ >O   À >A   Ã >A   Õ >O   ? >Y    ? >Y
    DATA 225,83,0,0
    '     ? >S

 I  hope  your  printer-driver could  digest  all  these  special
characters.  Other  special  characters  are  treated  as  space-
characters.

 If you have done your homework,  you should now be able to write
a  clever alphabetical sorting-program yourself.  You  wanted  to
become  an expert,  didn't you?  Here are a few ideas to get  you
started:

     ' Sort string-array txt$() with index-array; ascii|() must
                                                            exist
     last=DIM?(txt$())-1           ! index of last element
     DIM temp$(last),index%(last)
     FOR i=0 TO last               ! copy strings to temporary
                                                            array
       temp$(i)=txt$(i)
     NEXT i
     FOR i=0 TO last               ! fill index-array with
                                                          numbers
       index%(i)=i
     NEXT i
     QSORT temp$() WITH ascii|(),last+1,index%()
     ERASE temp$()                 ! remove temporary string
                                                            array
     FOR i=0 TO last
       PRINT txt$(index%(i))       ! check result (for speedy
                                                         readers)
     NEXT i

 Do   you  still  remember  I  told  you  there  are  two   extra
possibilities?  Well,  the second extra possibility with  string-
arrays  is  the  use  of  'OFFSET o'  to  ignore  the  first  'o'
characters  during  sorting.  Suppose you have created  an  array
files$() with FILES and would like to sort the files by length:

     files$="A:\FILES.DAT"
     DIM files$(200)               ! create directory-array
     FILES "A:\*.*" TO files$      ! send directory to file on
                                                             disk
     OPEN "I",#1,files$
     RECALL #1,files$(),-1,x%      ! put directory in array
     CLOSE #1
     KILL files$                   ! throw temporary file away
     QSORT files$() OFFSET 13,n    ! sort array by file-length

 The  first  character (either a space or '*') and  the  filename
(the next 12 characters) are ignored during sorting.

Binary search

 The  fastest way to locate an element in a sorted array  is  the
binary search:

     ' Locate element in sorted word-array numb()
     first=0
     last=PRED(DIM?(numb()))
     WHILE first<last
       middle=DIV(ADD(first,last),2)
       IF element>numb(middle)
         first=SUCC(middle)
       ELSE
         last=middle
       ENDIF
     WEND
     ok!=(numb(first)=element)
     IF ok!
       index=first                 ! found the element at index
       PRINT index
     ELSE
       PRINT "not found"
     ENDIF

                     Procedures (CHAPTER.05)

Ascii_qsort and Init_ascii_array                         ASCIQSRT
 Sort  one-dimensional string-array  alphabetically,  with  byte-
array ascii|() taking care of special characters:
     @ascii_qsort(-1,array$())        ! -1 = entire array
 If the global array ascii|() didn't exist, it's first created by
the Procedure Init_ascii_array.  If you don't want to disturb the
original    string-array,    you    can   use    the    Procedure
String_index_qsort.

Bin_search_string                                         BIN_STR
 Find  a particular string in a sorted string-array with  'binary
search':
     element$="Han Kempen"
     @bin_search_string(TRUE,element$,names$(),index,found!)
     IF found!
       PRINT "String """;element$;""" has index ";index
     ELSE
       PRINT "String """;element$;""" not found in array"
     ENDIF
 If  the lowercase-switch is TRUE the Procedure searches  for  an
exact  fit,  so a string like "HAN KEMPEN" is ignored.  With  the
lowercase-switch FALSE,  all strings are converted to upper  case
before comparison, so "HAN KEMPEN" is now recognised as a hit. If
the   search   was  not   successful,   the   Procedure   returns
found!=FALSE.

Bin_search_word                                          BIN_WORD
 Find  a  particular  word in a sorted  word-array  with  'binary
search':
     element=25
     @bin_search_word(element,numbers&(),index,found!)
     IF found!
       PRINT "Element ";element;" has index ";index
     ELSE
       PRINT "Element ";element;" not found in array"
     ENDIF

Bubble_sort                                              BUBL_SRT
 Sort word-array with 'Bubble Sort':
     @bubble_sort(numbers&())
 Very slow. Only suitable for small arrays or for arrays that are
almost sorted already.

Comb_sort                                                COMB_SRT
 Sort word-array with 'Combsort':
     @comb_sort(numbers&())
 Simple and reasonably fast. This is a much improved Bubble Sort.

Insert_sort                                               INS_SRT
 Sort word-array with 'Insert Sort':
     @insert_sort(numbers&())

Iter_quick_sort                                          ITER_SRT
 Sort word-array with iterative 'Quick Sort':
     @iter_quick_sort(numbers&())
 Uses less memory than Quick_sort.

Quick_sort and Quick                                     QUIK_SRT
 Sort word-array with recursive 'Quick Sort':
     @quick_sort(numbers&())
 This Procedure uses the same algorithm as QSORT.  Because of the
recursion  (Procedure  calling itself repeatedly) you  could  run
into trouble with large arrays.  In that case Iter_quick_sort  is
more suitable.

Selection_sort                                            SEL_SRT
 Sort word-array with 'Selection Sort':
     @selection_sort(numbers&())

Shell_sort                                               SHEL_SRT
 Sort word-array with 'Shell Sort':
     @shell_sort(numbers&())
 This Procedure uses the same algorithm as SSORT.

String_index_qsort and Init_ascii_array                  STR_INDX
 Use an index-array to sort a string-array:
     @string_index_qsort(TRUE,name$(),index%())
     FOR i=0 TO DIM?(name$())-1
       PRINT name$(index%(i))
     NEXT i
 The string-array itself is not sorted.  The index-numbers of the
sorted array are returned in the array index%().  If the flag  is
TRUE,  the global array ascii|() is used to take care of  special
characters (Procedure Init_ascii_array is called). If the flag is
FALSE,  special characters are ignored and lower case  characters
(ASCII-values  97-122)  are not treated the same  as  upper  case
characters (ASCII-values 65-90). 

Disclaimer
The text of the articles is identical to the originals like they appeared in old ST NEWS issues. Please take into consideration that the author(s) was (were) a lot younger and less responsible back then. So bad jokes, bad English, youthful arrogance, insults, bravura, over-crediting and tastelessness should be taken with at least a grain of salt. Any contact and/or payment information, as well as deadlines/release dates of any kind should be regarded as outdated. Due to the fact that these pages are not actually contained in an Atari executable here, references to scroll texts, featured demo screens and hidden articles may also be irrelevant.