Jürgen Plate

Suchen und Sortieren in Pascal und Basic

1. Teil
In der folgenden Serie sollen die wichtigsten Verfahren zum Sortieren von Daten und zum Suchen nach einem bestimmten Element einer Datenmenge vorgestellt werden. Die Anwendungsbereiche dafür lassen in ihrer Vielzahl nichts zu wünschen übrig. Gleichzeitig sind es aber auch die Sortier- und Suchalgorithmen, die die meiste Rechenzeit vieler Programme verschlingen, und so ist gerade hier die Notwendigkeit am größten, einen effizienten Algorithmus zu finden. Alle hier vorgestellten Algorithmen sind getestete Unterprogramme; abgefaßt in den beiden Programmiersprachen Pascal und Basic. Die Verbreitung dieser Sprachen im Mini- und Mikrocomputerbereich läßt fast immer eine direkte Verwendung der Unterprogramme zu. In allen Programmen wurde auf Klarheit und Übersichtlichkeit geachtet, so daß eine Adaption an einen bestimmten „Dialekt" oder die Übertragung in eine andere Programmiersprache keine Schwierigkeiten bereiten dürfte.

Die wichtigsten Anweisungsstrukturen von Pascal und Basic

Die Erläuterung der Algorithmen erfolgt an den Pascal-Unterprogrammen, da bei dieser Sprache die Daten- und Anweisungsstrukturen wesentlich übersichtlicher sind. Für diejenigen unter Ihnen, denen Pascal nicht so geläufig ist, sind die wichtigsten Anweisungsstrukturen der beiden Sprachen in Tabelle 1 einander gegenübergestellt.

Tabelle 1: Anweisungsstrukturen

Pascal Basic

IF <Bedingung> THEN
    <Anweisung 1>
ELSE
    <Anweisung 2>;
100 IF <Bedingung> THEN 300
200 <Anweisung 2>
250 GOTO 400
300 <Anweisung 1>
400 REM Hier geht es weiter

WHILE <Bedingung> DO
    <Anweisung>;
100 IF NOT <Bedingung> THEN 400
200 <Anweisung>
300 GOTO 100
400 REM Hier geht es weiter

REPEAT
    <Anweisung(en)>
UNTIL <Bedingung>;
100 <Anweisung(en)>
200 IF NOT <Bedingung> THEN 100

FOR <Variable>:=<Wert> TO
   <Endwert> DO <Anweisung>;
100 FOR <Variable>=<Wert> TO <Endwert>
200 <Anweisung>
300 NEXT <Variable>
 
<Wert> und <Endwert> können Ausdrücke sein

Sollen in Pascal hinter den Schlüsselworten THEN, ELSE oder DO mehrere Anweisungen stehen, so sind diese mit den Schlüsselworten BEGIN und END zu „klammern". Sie sehen das in den Programmen. Die Schlüsselworte zur Datendefinition und -Strukturierung (CONST, TYPE und VAR) brauchen Sie als Basic-Programmierer nicht; die Erklärungen zu den Programmen verwenden sie zwar, sind aber auch für „Nur-Basic-Programmierer" gut zu verstehen.

Alle Pascal-Unterprogramme werden mit dem Schlüsselwort PROCEDURE eingeleitet und die „von außen" kommenden Variablen als Parameter mitgegeben. So ist zum Beispiel bei der

     PROCEDURE SORT (VAR D:DATA);

zum Sortieren der Kundendaten der Aufruf

     SORT(KUNDEN);

irgendwo im Hauptprogramm möglich.

Haben die Lieferanten den gleichen Aufbau (die gleiche Struktur) wie die Kunden, können auch diese mit

     SORT(LIEFERANTEN);

sortiert werden. Dieser Prozedurmechanismus hat einen weiteren Vorteil: Alle innerhalb der Prozedur definierten Variablen haben nur innerhalb der Prozedur Gültigkeit und sind nur dort vorhanden. Gleichnamige Variablen des Hauptprogramms werden nicht beeinflußt. In Basic ist ein derartiger Mechanismus nicht verfügbar (leider!).

Datenstrukturen und ihre Realisierung in den beiden Sprachen

Grundsätzlich wird die zu sortierende Information unterteilt in das Such- oder Sortierkriterium (Schlüssel, Key) und die eigentliche Information. Zum Beispiel ist bei einem Datensatz der Kundendatei der Schlüssel die Kundennummer. Die Information besteht aus Namen, Adresse, Bankverbindung, offenen Rechnungen usw.

Es ist aber in manchen Fällen möglich, daß der Schlüssel gleichzeitig die einzige Information darstellt (z.B. Namenslisten). In den Programmen wird als Schlüssel eine Integerzahl (Ganzzahl) verwendet; sie läßt sich natürlich durch jede andere Datenstruktur ersetzen, die direkte Vergleiche zuläßt. Als Information wird in den Programmen eine Zeichenkette (String) verwendet. In Pascal sieht das dann so aus wie in Tabelle 2.

Tabelle 2: Datentyp-Definition in Pascal

TYPE ITEM = RECORD
      KEY : INTEGER;
     INFO : PACKED ARRAY [1..10] OF CHAR
            END;

Bei der Variablen des Types ITEM werden durch die Wertzuweisung V1 := V2 alle Teile des Records (also KEY und INFO) von V1 nach V2 gebracht. Die einzelnen Komponenten von V1 lassen sich durch den Selektionsmechanismus V1.KEY bzw. V1.INFO ansprechen.

In Basic gibt es keine derartige Datenstrukturierungsmöglichkeit. Es werden hier als Behelf zwei getrennte Variablen verwendet:

K für den Schlüssel (Key)
I$ für die Information (Info)

Ist der Schlüssel gleichzeitig die einzige Information, vereinfacht sich die Struktur natürlich erheblich. Die einzelnen Datensätze werden in linearen Feldern (Arrays) gespeichert. So ergeben sich die Programme in Tabelle 3.

Tabelle 3: Datentypen-Definition im Programm

Pascal Basic

CONST N =      1000; (* Feldlänge *)
TYPE STRING =  PACKED ARRAY [1...10] OF CHAR;
TYPE ITEM =    RECORD
                  KEY : INTEGER;
                  INFO : STRING
               END;
     DATA : ARRAY [1..N] OF ITEM;
 VAR D : DATA;
10 N = 1000
20 REM N ist als konstant
30 REM   zu betrachten
40 DIM K(1000), I$(1000)

Programmerstellung, Effizienzvergleich

Es wurde versucht, die Programme so übersichtlich wie möglich und möglichst universell verwendbar zu machen. So wurde in Basic auf die Besonderheiten bestimmter Dialekte verzichtet. In den Pascal-Listings wurden die Schlüsselworte (BEGIN, END usw.) aus Gründen der Übersichtlichkeit fett gedruckt. Ebenso sind in den Programmtext erläuternde Kommentare (*...*) eingefügt.

Der Aufruf der Pascal-Prozeduren erfolgt wie üblich durch den Namen, der Aufruf der Basic-Unterprogramme geschieht einheitlich mit GOSUB. Für jedes Pascal-Unterprogramm wurde die Effizienz in Form einer Zeitmessung geprüft: Die Rechenzeit wurde einmal für die Bearbeitung von 100 und einmal für die Bearbeitung von 1000 Feldelementen durchgeführt. Dabei wurde jeder Datensatz einmal sortiert, einmal umgekehrt sortiert und einmal rein zufällig angeordnet von dem Programm bearbeitet.

Da die Basic-Programme aus den Pascal-Algorithmen entwickelt wurden, lassen sich die Ergebnisse des Effizienzvergleichs der einzelnen Sortierverfahren im Groben auch auf die Basic-Programme übertragen.

Sortieren

Jetzt kann's losgehen - wir haben Datentypen definiert und somit die Grundlage geschaffen, mit diesen Daten irgend etwas anzufangen. Wenden wir uns zunächst dem Sortieren von Feldern zu. Später werden wir einen Effizienzvergleich der besprochenen Verfahren anstellen.

Lineares Einfügen

Dieses einfachste aller Sortierverfahren nimmt beginnend bei I=2 das I-te Datenelement und fügt es an der entsprechenden Stelle im Datenfeld ein. Danach wird I um 1 erhöht und solange fortgefahren, bis alle Datenelemente bearbeitet sind. Sind nur wenige Daten zu sortieren, hat auch dies einfache Verfahren durchaus seine Berechtigung. Der Algorithmus lautet also:

     FOR I := 2 TO N DO
         (* füge den Wert von D[I] an entsprechender
            Stelle in D[1]...D[I] ein *)

Das Einfügen geschieht, indem für J von I-1 ausgehend das Element D[I] mit dem Element D[J] verglichen wird und dann entweder D[I] eingefügt oder D[J] nach rechts verschoben wird. Also muß das Element D[I] vorher auf einer Hilfsvariablen gespeichert werden. Bild 1 zeigt die Pascal-Prozedur und Bild 2 das Basic-Unterprogramm.

PROCEDURE LINSORT (VAR D : DATA);
   (* SORTIEREN DES FELDES D NACH DEN SCHLUESSELN D[..].KEY
      IN AUFSTEIGENDER FOLGE.
      GLOBALE KONSTANTE : N FELDLAENGE
      GLOBALE TYPEN: ITEM = RECORD KEY : ...; INFO : ... END;
                     DATA = ARRAY [1..N] OF ITEM;
   *)
   VAR I,J :0..N;
       H : ITEM;
       ENDE : BOOLEAN;
   BEGIN
   FOR I := 2 TO N DO
     BEGIN
     ENDE := FALSE;
     H := D[I];
     J := I - 1;
     WHILE NOT ENDE AND (J>0) DO
       IF H.KEY < D[J].KEY THEN (* WEITERSUCHEN *)
          BEGIN D[J+1] := D[J]; J := J - 1 END
       ELSE ENDE := TRUE;
     D[J+1] := H;
     END
   END (* LINSORT *);
Bild 1. Pascal-Programm für lineares Sortieren eines Datenfeldes

10000 REM * * * * * * * * * * LINSORT * * * * * * * * * *
10001 REM * SORTIEREN DES FELDES I$ NACH DEN SCHLUESSELN
10002 REM * IN DEM FELD K.
10003 REM * DIE ELEMENTE K(J) UND I$(J) BILDEN EIN PAAR
10004 REM * SCHLUESSEL - INFORMATION.
10005 REM * DIE UNTERE FELDGRENZE IST 1, DIE OBERE FELD-
10006 REM * GRENZE STEHT IN DER VARIABLEN N.
10010 FOR I = 2 TO N
10020   H$ =I$(I)
10030   H = K(I)
10040   J=I-1
10050 IF H>=K(J) THEN 10100
10060   K(J+1)=K(J)
10070   I$(J+1)=I$(J)
10080   J = J - 1
10090   IF J<>0 THEN 10050
10100   K(J+1) = H
10110   I$(J+1) = H$
10120 NEXT I
10130 RETURN
10140 REM * * * * * * * * * * * * * *
Bild 2. Basic-Unterprogramm für lineares Sortieren von Feldvariablen

Binäres Einfügen

Der vorhergehende Algorithmus läßt sich verbessern, indem die bereits vorhandene Ordnung der Elemente D[1] bis D[I] ausgenützt wird, um die Einfügungsstelle zu finden. Beim binären Einfügen wird in der Mitte der Elemente D[1] bis D[I] geprüft, ob H in der unteren oder in der oberen Hälfte eingefügt werden muß. Die entsprechende Teilfolge wird wieder halbiert, bis durch die Teilung die Einfügungsstelle gefunden worden ist.

Leider ergibt sich nur eine Reduzierung in der Zahl der Vergleiche, denn der Rest des Programms, also auch die Zahl der Verschiebungen, ist der gleiche wie bei der linearen Sortierung. Bild 3 enthält das Pascal-Listing, Bild 4 das Basic-Listing.

PROCEDURE BINARYSORT (VAR D : DATA);
   (* SORTIEREN DES FELDES D NACH DEN SCHLUESSELN D[..].KEY
      IN AUFSTEIGENDER FOLGE.
      GLOBALE KONSTANTE : N FELDLAENGE
      GLOBALE TYPEN: ITEM = RECORD KEY : ...; INFO : ... END;
                     DATA = ARRAY [1..N] OF ITEM;
   *)
   VAR I,J,L,R,M : 0..N;
       H : ITEM;
   BEGIN
   FOR I := 2 TO N DO
   BEGIN
     J := I - 1;
     L := 1; R:=J;
     H := D[I];
     WHILE L <= R DO (* BINAERE SUCHE *)
       BEGIN
       M := (L + R) DIV 2;
       IF H.KEY < D[M].KEY THEN R := M - 1 ELSE L := M + 1;
       END;
     WHILE J >= L DO (* VERSCHIEBEN *)
       BEGIN D[J+1] := D[J]; J :=J - 1 END;
     D[L] := H;
     END;
   END (* BINARYSORT *);
Bild 3. Sortieren durch binäres Einfügen in Pascal

20000 REM * * * * * * * * * * BINARY SORT * * * * * * * * * *
20001 REM * SORTIEREN DES FELDES I$ NACH DEN SCHLUESSELN
20002 REM * IN DEM FELD K.
20003 REM * DIE ELEMENTE K(J) UND I$(J) BILDEN EIN PAAR
20004 REM * SCHLUESSEL - INFORMATION.
20005 REM * DIE UNTERE FELDGRENZE IST 1, DIE OBERE FELD-
20006 REM * GRENZE STEHT IN DER VARIABLEN N.
20010 FOR I = 2 TO N
20020   L=1
20030   R= I - 1
20040   H$ = I$(I)
20050   H = K(I)
20060   REM * * * BINAERE SUCHE * * *
20070   IF L>R THEN 20140
20080   M= INT( (L+R)/2 )
20090   IF H<K(M) THEN 20120
20100   L=M+1
20110   GOTO 20070
20120   R = M-1
20130   GOTO 20070
20140   FOR J = I-1 TO L STEP -1
20150     I$(J+1) = I$(J)
20160     K(J+1) = K(J)
20170   NEXT J
20180   I$(L) = H$
20190   K(L) = H
20200 NEXT I
20210 RETURN
20220 REM * * * * * * * * * * * * * * * *
Bild 4. Basic-Programm zum Sortieren durch binäres Einfügen

Bubblesort und Shakersort

Bei diesen beiden Verfahren wird wie bei den vorhergehenden das Feld mehrfach durchlaufen. Anstelle des Einfügens des entsprechenden Feldelements an der richtigen Stelle wird hier das jeweils kleinste Element durch Austausch mit dem Nachbarn an die passende Stelle gebracht. Wenn man das Feld vertikal aufschreibt, „perlt" das Feldelement nach oben an seinen Platz, und das hat diesem Verfahren den Namen eingetragen. In der Pascal-Version wird der Austausch durch die Prozedur SWAP erledigt, in der Basic-Version sind die Operationen in das Programm eingefügt (Bild 5 und Bild 6).

PROCEDURE BUBBLESORT(VAR D : DATA);
   (* SORTIEREN DES FELDES D NACH DEN SCHLUESSELN D[..].KEY
      IN AUFSTEIGENDER FOLGE.
      GLOBALE KONSTANTE : N FELDLAENGE
      GLOBALE TYPEN: ITEM = RECORD KEY : ... INFO : .... END;
                     DATA = ARRAY [1..N] OF ITEM;
   *)
   VAR J,I : 0..N;
   PROCEDURE SWAP(VAR X,Y : ITEM);
     VAR Z : ITEM;
     BEGIN Z := X; X := Y; Y := Z END;
   BEGIN
   FOR I := 2 TO N DO
     FOR J := N DOWNTO I DO
       IF D[J-1].KEY > D[J].KEY THEN SWAP(D[J],D[J-1]);
   END (* BUBBLESORT *);
Bild 5. Pascal-Prozedur für „Bubblesort" (Blasen-Sortieren)

30000 REM * * * * * * * * * * BUBBLESORT * * * * * * * * * *
30001 REM * SORTIEREN DES FELDES I$ NACH DEN SCHLUESSELN
30002 REM * IN DEM FELD K.
30003 REM * DIE ELEMENTE K(J) UND I$(J) BILDEN EIN PAAR
30004 REM * SCHLUESSEL - INFORMATION.
30005 REM * DIE UNTERE FELDGRENZE IST 1, DIE OBERE FELD-
30006 REM * GRENZE STEHT IN DER VARIABLEN N.
30010 FOR I = 2 TO N
30020    FOR J = N TO I STEP -1
30030       IF K(J-1)>K(J) THEN 30050
30040       GOTO 30110
30050       H$ = I$(J)
30060       H = K(J)
30070       I$(J) =I$(J-1)
30080       K(J) = K(J-1)
30090       I$(J-1) = H$
30100       K(J-1) = H
30110    NEXT J
30120 NEXT I
30130 RETURN
30140 REM * * * * * * * * * * * * * * * *
Bild 6. Bubblesort auf einem Basic-Computer

Wenn Sie den Algorithmus auf die Möglichkeit der Verbesserung hin untersuchen, fällt Ihnen sicher gleich die feste Schleifenstruktur auf, die keine Rücksicht auf schon sortierte Sequenzen nimmt. Die erste Verbesserung ist dadurch möglich, wenn das Programm abbricht, wenn das Feld sortiert ist. Das ist der Fall, wenn in einem Durchlauf für I kein Austausch erfolgte. Weiterhin ist Bubblesort höchst asymmetrisch, wenn Sie zum Beispiel die beiden folgenden Felder betrachten, können Sie feststellen, daß D1 schon nach einem Durchlauf, D2 dagegen erst nach sieben Durchläufen sortiert ist.

     D1: 10  25  36  54  87   2
     D2: 87   2  10  25  36  54

Die Asymmetrie läßt sich beseitigen, indem in aufeinanderfolgenden Durchläufen jeweils in entgegengesetzter Richtung gearbeitet wird. Dieses „Auf" und „Ab" hat dem Verfahren auch zu dem Namen Shakersort verholfen. Eine letzte Verbesserung ergibt sich, wenn man den Index festhält, bis zu dem das Feld schon sortiert ist. Das Ergebnis der Verbesserung von Bubblesort finden Sie in Bild 7 und Bild 8.

PROCEDURE SHAKERSORT (VAR D : DATA);
   (* SORTIEREN DES FELDES D NACH DEN SCHLUESSELN D[..].KEY
      IN AUFSTEIGENDER FOLGE.
      GLOBALE KONSTANTE : N FELDLAENGE
      GLOBALE TYPEN: ITEM = RECORD KEY : ...; INFO : ... END;
                     DATA = ARRAY [1..N] OF ITEM;
   *)
     VAR I,J,R,L : 0..N;
     PROCEDURE SWAP(VAR X,Y : ITEM);
       VAR Z : ITEM;
       BEGIN Z := X; X := Y; Y := Z END;
     BEGIN
     L := 2; R := N; I := N - 1;
     REPEAT
       FOR J := R DOWNTO L DO (* RAUFSCHUETTELN *)
         BEGIN
         IF D[J-1].KEY > D[J].KEY THEN
            BEGIN SWAP(D[J],D[J-1]); I := J (* INDEX MERKEN *) END;
         END;
       L := I + 1;
       FOR J := L TO R DO (* RUNTERSCHUETTELN *)
     BEGIN
      IF D[J-1].KEY > D[J].KEY THEN
         BEGIN SWAP(D[J],D[J-1]); I :=J (* INDEX MERKEN *) END;
     END;
     R := I - 1;
   UNTIL L > R;
   END;
Bild 7. Pascal-Prozedur für „Shakersort"

40000 REM * * * * * * * * * * SHAKERSORT * * * * * * * * * *
40001 REM * SORTIEREN DES FELDES I$ NACH DEN SCHLUESSELN 
40002 REM * IN DEM FELD K.
40003 REM * DIE ELEMENTE K(J) UND I$(J) BILDEN EIN PAAR
40004 REM * SCHLUESSEL - INFORMATION.
40005 REM * DIE UNTERE FELDGRENZE IST 1, DIE OBERE FELD- 
40006 REM * GRENZE STEHT IN DER VARIABLEN N.
40010 L = 2
40020 R = N
40030 I = N - 1
40040 REM BEGINN DER REPEAT- SCHLEIFE, ENDE BEI 40170
40050 FOR J = R TO L STEP -1
40060   IF K(J-1) <= K(J) THEN 40090
40070   GOSUB 40190
40075   REM GO AND SWAP D(J) WITH D(J-1)
40080   I = J
40090 NEXT J
40100 L = I + 1
40110 FOR J = L TO R
40120   IF K(J-1)<=K(J) THEN 40150
40130   GOSUB 40190
40140   I = J
40150 NEXT J
40160 R = I - 1
40170 IF L <= R THEN 40040
40180 RETURN
40190 REM * * SWAP (D(I),D(J-1))
40200 H$ = I$(J)
40210 H = K(J)
40220 I$(J) = I$(J-1)
40230 K(J) = K(J-1)
40240 I$(J-1) = H$
40250 K(J-1) = H
40260 RETURN
40270 REM * * * * * * * * * * * * * * * *
Bild 8. Basic-Unterprogramm für das Shaker-Sortierverfahren

Im übrigen sind von Bubblesort und Shakersort keine besonders große Verbesserungen zu erwarten. Shakersort ist jedoch bei weitgehend sortierten Feldern zu empfehlen.

Mit diesen beiden Verfahren sind die einfachen Sortiermethoden abgeschlossen. Die beiden folgenden sehr effizienten Sortierverfahren sind in ihrem Algorithmus wesentlich komplizierter und finden hauptsächlich dann Anwendung, wenn es darum geht, sehr große Datenmengen zu sortieren.

Heapsort

Die bisher behandelten Algorithmen suchten immer nur ein Element, das kleinste aus der Restmenge von N-1 Elementen heraus. Die Sortiermethode läßt sich also nur beschleunigen, indem bei einem Durchlauf mehr Information gesammelt wird. Eine Sortiermethode, die nach diesem Schema verfährt, ist das Sortieren mit Bäumen. Dabei wird als Baum die unten gezeigte Anordnung der Elemente einer Datenmenge bezeichnet. Betrachten Sie dazu die Folge von Schlüsseln:

     40 50 10 45 90 15  5 65

Ordnet man diese Elemente in einem Baum derart, daß immer das kleinere Element als Wurzel verwendet wird, benötigt man N-1 Vergleiche (Bild 9).

Bild 9. Beim Heap-Sortierverfahren benötigt man für N Elemente stets N-1 Vergleiche

Wenn ein solcher binärer (= zweiästiger) Baum in einem linearen Feld gespeichert werden soll, ergibt sich die Bedingung:

     d [i] <= d [2i] und d [i] <= d [2i+1]

(Die Feldkomponenten stehen unter den Schlüsseln.) Eine derartige Anordnung der Schlüssel heißt HEAP. Angenommen, der Heap (Bild 10) soll um ein Element (d1 = 40) erweitert werden.

Bild 10. Erweiterung eines „Heap" um das Element d1 = 40

Das neue Element (z.B.: d1 = 40) wird zuerst einmal an die Spitze gesetzt. Dann läßt man es entlang der kleineren Elemente nach unten wandern, wobei die kleineren Elemente gleichzeitig nach oben steigen (Bild 11).

Bild 11. Sortierschritte beim Einfügen des neuen Elements 40

Das Sortierverfahren von Heapsort (Tabelle 4) besteht also aus zwei getrennten Tätigkeiten:

Tabelle 4: Pascal-Programm HEAPSORT

PROCEDURE HEAPSORT (VAR D : DATA);
  .
  .
  .
BEGIN
L := (N DIV 2) + 1; (* BINAERER BAUM! *)
R := N;
REPEAT
  IF L>1 THEN
     (* HEAP AUFBAUEN *)
     L:=L-1
  ELSE
     IF R>1 THEN
        (* HEAP ABARBEITEN *)
        BEGIN SWAP (D[L], D[R]); R := R-1 END;
     (* NAECHSTES HEAPELEMENT DURCH DEN HEAP
     WANDERN LASSEN, SIEHE OBEN *)
UNTIL R =1
END;

Die fertige Prozedur ist in Bild 12, das entsprechende Basic-Programm in Bild 13 aufgelistet.

PROCEDURE HEAPSORT (VAR D : DATA);
   (* SORTIEREN DES FELDES D NACH DEN SCHLUESSELN D[..].KEY
      IN AUFSTEIGENDER FOLGE.
      GLOBALE KONSTANTE : N FELDLAENGE
      GLOBALE TYPEN: ITEM = RECORD KEY : ...; INFO : .... END;
                     DATA = ARRAY [1..N] OF ITEM;
   *)
   VAR I,J,R,L : INTEGER;
       H : ITEM;
       CONTINUE : BOOLEAN (* STOPPER FUER DIE WANDERUNG *);
   PROCEDURE SWAP(VAR X,Y : ITEM);
      VAR Z : ITEM;
      BEGIN Z := X; X := Y; Y := Z END;
   BEGIN
   L := (N DIV 2) + 1; R := N;
   REPEAT
      IF L > 1 THEN
        L := L - 1
      ELSE
        IF R > 1 THEN
            BEGIN SWAP(D[L],D[R]); R := R - 1; END;
      (* WANDERN DES NAECHSTEN ELEMENTS DURCH DEN HEAP *)
      I := L; J := 2*I;
      H := D[I];
      CONTINUE := J <= R;
      WHILE CONTINUE DO
       BEGIN
       IF J < R THEN (* DANN DARF D[J] MIT D[J+1] VERGLICHEN WERDEN *)
          IF D[J].KEY < D[J+1].KEY THEN J := J + 1;
       IF J<=R THEN (* VERGLEICH H<D[J].KEY ZULAESSIG *)
          CONTINUE := H.KEY < D[J].KEY ELSE CONTINUE := FALSE;
       IF CONTINUE THEN
          BEGIN (* EINORDNEN *)
          D[I] := D[J];
          I := J; J := 2*I ;
          END;
       END (* WHILE CONTINUE *);
     D[I] := H;
   UNTIL R = 1;
   END (* HEAPSORT *);
Bild 12. Die fertige Heapsort-Prozedur in Pascal

50000 REM * * * * * * * * * * HEAPSORT * * * * * * * * *
50001 REM * SORTIEREN DES FELDES I$ NACH DEN SCHLUESSELN
50002 REM * IN DEM FELD K.
50003 REM * DIE ELEMENTE K(J) UND I$(J) BILDEN EIN PAAR
50004 REM * SCHLUESSEL - INFORMATION.
50005 REM * DIE UNTERE FELDGRENZE IST 1, DIE OBERE FELD-
50006 REM * GRENZE STEHT IN DER VARIABLEN N.
50010 L = INT(N/2) + 1
50015 REM IN PASCAL L = N DIV 2+ 1
50020 R = N
50030 IF L>1 THEN 50130
50035 REM BAUM AUFBAUEN
50040 IF R<=1 THEN 50120
50050 H$=I$(L)
50060 H = K(L)
50070 I$(L)=I$(R)
50080 K(L)=K(R)
50090 I$(R)=H$
50100 K(R)=H
50110 R=R - 1
50120 GOTO 50140
50130 L=L-1
50140 REM W A N D E R N
50150 I=L
50160 J=2*I
50170 H=K(I)
50180 H$=I$(I)
50190 IF J>R THEN 50280
50200 IF J>=R THEN 50220
50205 IF K(J)>=K(J+1) THEN 50220
50210 J = J + 1
50220 IF J>R THEN 50280
50225 IF H>=K(J) THEN 50280
50230 I$(I)=I$(J)
50240 K(I)=K(J)
50250 I=J
50260 J=2*I
50270 GOTO 50200
50280 I$(I)=H$
50290 K(I)=H
50300 IF R<> 1 THEN 50030
50310 RETURN
50320 REM * * * * * * * * * * * * * * * *
Bild 13. Heapsort läßt sich auch in Basic relativ einfach programmieren

Diese Prozedur hat noch eine schöne Eigenschaft. Wenn man bei den zwei Zeilen
     IF D[J].KEY<D[J+1].KEY THEN J:=J+1;
     CONTINUE := H.KEY<D[J].KEY ELSE
     CONTINUE := FALSE;

die Kleinerzeichen durch Größerzeichen ersetzt, wandert das größere Element nach oben und das Feld wird dann absteigend, also genau umgekehrt sortiert; im Basic-Programm sind das die Zeilen 50205 und 50225. Als letztes Sortierverfahren folgt im nächsten Heft Quicksort.

[Inhalt] [2. Teil]

Eingescanned von Werner Cirsovius
September 2002
© Franzis' Verlag