home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / extra18 / grdlagen / sort / hrs.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-01-28  |  14.6 KB  |  527 lines

  1. (* ------------------------------------------------- *)
  2. (*                      HRS.PAS                      *)
  3. (*            (c) 1992 H.Rüter & DMV-Verlag          *)
  4. (* ------------------------------------------------- *)
  5. (*       Sortierroutinen für Listen und Arrays       *)
  6. (* ------------------------------------------------- *)
  7. (*$R-,S-,I-,V-,B-,O-,A+,D+ *)
  8.                     (* Größtmögliche Geschwindigkeit *)
  9. UNIT HRS;
  10.  
  11. INTERFACE
  12.  
  13. TYPE
  14.   SetOfChar = SET OF CHAR;
  15.  
  16.   CompTyp   = (Kleiner, Gleich, Groesser);
  17.                     (* Für die Element-Vergleiche    *)
  18.  
  19.   ListTyp   = (Einfach, Doppelt);
  20.                 (* Einfache oder doppelte Verkettung *)
  21.  
  22.   SortFunc  =
  23. (*$IFDEF VER40 *)
  24.               Pointer;
  25. (*$ELSE *)
  26.               Function(El1, El2 : Pointer;
  27.                        CompPara : WORD) : CompTyp;
  28. (*$ENDIF *)
  29.  
  30. CONST
  31.   MaxIndex  = 16000;
  32.              (* Maximalzahl zu sortierender Elemente *)
  33.              (* Bei Compiler-Meldung "Structure too  *)
  34.              (* large" verkleinern                   *)
  35.  
  36.   SortOkay       = 0;            (* Fehlerkonstanten *)
  37.   MemError       = 1;
  38.   ToMuchElements = 2;
  39.  
  40. (* --- Hilfsroutinen  für die Testprogramme          *)
  41.  
  42. FUNCTION  GetChar(Menge : SetOfChar) : CHAR;
  43. PROCEDURE DummyRead;
  44. FUNCTION  Min(A, B : WORD) : WORD;
  45.  
  46. (* --- Vergleichsroutinen                            *)
  47.  
  48. FUNCTION  Compare(VAR X, Y; Size : WORD) : BOOLEAN;
  49.  
  50. FUNCTION  Equal(VAR X, Y; Size : WORD) : CompTyp;
  51.  
  52. (* ------------------------------------------------- *)
  53.  
  54. FUNCTION SortError : BYTE;
  55. (*  Gibt letzten FehlerStatuswert zurück             *)
  56.  
  57. (* ------------------------------------------------- *)
  58.  
  59. (* ------------------------------------------------- *)
  60. (*    Sortierroutinen für Listen                     *)
  61. (*                                                   *)
  62. (*    Liste    --> Zeiger auf den Listenanfang       *)
  63. (*    LTyp     --> doppelt oder einfach verkettete   *)
  64. (*                 Liste                             *)
  65. (*    CompF    --> Vergleichsfunktion vom Typ        *)
  66. (*                 »SortFunc«                        *)
  67. (*    CompPara --> Parameter zur Steuerung der       *)
  68. (*                 Vergleichsfunktion                *)
  69. (*                                                   *)
  70. (* Falls ein Fehler auftritt, wird die Liste unver-  *)
  71. (* ändert gelassen.                                  *)
  72. (* Fehlerabfrage durch Funktion »SortError«.         *)
  73. (* ------------------------------------------------- *)
  74.  
  75. PROCEDURE AuswahlSort(VAR Liste    : Pointer;
  76.                           LTyp     : ListTyp;
  77.                           CompF    : SortFunc;
  78.                           CompPara : WORD);
  79.  
  80. PROCEDURE AustauschSort(VAR Liste    : Pointer;
  81.                             LTyp     : ListTyp;
  82.                             CompF    : SortFunc;
  83.                             CompPara : WORD);
  84.  
  85. PROCEDURE EinfuegeSort(VAR Liste    : Pointer;
  86.                            LTyp     : ListTyp;
  87.                            CompF    : SortFunc;
  88.                            CompPara : WORD);
  89.  
  90. PROCEDURE QuickSort(VAR Liste    : Pointer;
  91.                         LTyp     : ListTyp;
  92.                         CompF    : SortFunc;
  93.                         CompPara : WORD);
  94.  
  95. (* ------------------------------------------------- *)
  96. (*    Sortierroutine für Array                       *)
  97. (*                                                   *)
  98. (*    APtr     --> Zeiger auf das Array              *)
  99. (*    ASize    --> Größe des Arrays (von 1 .. ASize) *)
  100. (*    ElSize   --> Größe eines Arrayelements         *)
  101. (*    CompF    --> Vergleichsfunktion vom Typ        *)
  102. (*                 »SortFunc                         *)
  103. (*    CompPara --> Parameter zur Steuerung der       *)
  104. (*                 Vergleichsfunktion                *)
  105. (*                                                   *)
  106. (* Falls ein Fehler auftritt, wird die Liste unver-  *)
  107. (* ändert gelassen.                                  *)
  108. (* Fehlerabfrage durch Funktion »SortError«.         *)
  109. (* ------------------------------------------------- *)
  110.  
  111. PROCEDURE ArraySort(APtr   : Pointer; ASize : WORD;
  112.                     ElSize : WORD;    CompF : SortFunc;
  113.                     CompPara : WORD);
  114.  
  115. (* ------------------------------------------------- *)
  116.  
  117. IMPLEMENTATION
  118.  
  119. USES Crt;
  120.  
  121. TYPE
  122.   Index    = 0..MaxIndex;
  123.  
  124.   SPtr     = ^SortPtr;
  125.             (* Hilfstypen zur Bearbeitung der Listen *)
  126.  
  127.   SortPtr  = RECORD (* Prototyp eines Listenelements *)
  128.                Next, Last : SPtr;
  129.              END;
  130.  
  131.   SortArray = ARRAY [1..MaxIndex] OF Pointer;
  132.                          (* Das zu sortierende Array *)
  133.   ArrayPtr  = ^SortArray;
  134.                          (* .. und der Zeiger darauf *)
  135.  
  136. CONST
  137.   SError : BYTE = 0;     (* Fehlervariable           *)
  138.  
  139. VAR
  140.   CompFunc : SortFunc;
  141.  
  142. (* ------------------------------------------------- *)
  143. (* Die nächsten beiden Routinen sind für die Version *)
  144. (* 4.0 von Turbo-Pascal implementiert worden, um     *)
  145. (* auch dort den Aufruf einer Routine mittels Zeiger *)
  146. (* zu ermöglichen.Beispiel : Routine Quicksort       *)
  147. (* ------------------------------------------------- *)
  148.  
  149. (*$IFDEF Ver40 *)
  150.   FUNCTION CallCompFunc(El1, El2 : Pointer;
  151.                         CompPara : WORD) : CompTyp;
  152.   INLINE($FF/$1E/CompFunc );   {Call Far }
  153.  
  154.   PROCEDURE InitSortFunc(P : SortFunc);
  155.   BEGIN
  156.     CompFunc := P;
  157.   END;
  158. (*$ENDIF *)
  159.  
  160. (* --- Externe Assembler-Routinen                    *)
  161.  
  162. (*$L Comp *)
  163.   FUNCTION  Compare(Var X, Y; Size : WORD) : BOOLEAN;
  164.   EXTERNAL;
  165.  
  166.   FUNCTION  Equal(VAR X, Y; Size : WORD) : CompTyp;
  167.   EXTERNAL;
  168.  
  169. (* ------------------------------------------------- *)
  170.  
  171.   FUNCTION GetChar(Menge : SetOfChar) : CHAR;
  172.   VAR
  173.     c : CHAR;
  174.   BEGIN
  175.     REPEAT
  176.       c := ReadKey;
  177.     UNTIL c IN Menge;
  178.     GetChar := c;
  179.   END;
  180.  
  181.   PROCEDURE DummyRead;
  182.   VAR
  183.     c : CHAR;
  184.   BEGIN
  185.     REPEAT
  186.       c := ReadKey;
  187.     UNTIL C <> #0;
  188.   END;
  189.  
  190.   FUNCTION Min(A, B : WORD) : WORD;
  191.   BEGIN
  192.     IF A < B THEN Min := A
  193.              ELSE Min := B;
  194.   END;
  195.  
  196. (* --- Fehlerabfrageroutine                          *)
  197.  
  198.   FUNCTION SortError : BYTE;
  199.   BEGIN
  200.     SortError := SError;
  201.     SError    := SortOkay;
  202.   END;
  203.  
  204.   FUNCTION ListSize(Liste : Pointer) : Longint;
  205.   (* Ermittelt die Anzahl der Listenelemente         *)
  206.   VAR
  207.     L : Index;
  208.     P : SPtr;
  209.   BEGIN
  210.     L := 0;
  211.     P := SPtr(Liste);
  212.  
  213.     WHILE P <> NIL DO BEGIN
  214.       Inc(L);
  215.       P := P^.Next
  216.     END;
  217.     ListSize := L;
  218.   END;
  219.  
  220.   PROCEDURE ArrayToListe(APtr      : ArrayPtr;
  221.                          ArraySize : LongInt;
  222.                          VAR Liste : Pointer;
  223.                              LTyp  : ListTyp);
  224.   VAR
  225.     L  : Index;
  226.     P1 : SPtr;
  227.   BEGIN
  228.     FOR L := 1 TO ArraySize DO BEGIN
  229.       P1 := APtr^[L];
  230.  
  231.       IF L < ArraySize THEN
  232.         P1^.Next := APtr^[Succ(L)]     (* Verkettung *)
  233.       ELSE
  234.         P1^.Next := NIL;
  235.  
  236.       IF LTyp = Doppelt THEN BEGIN
  237.         IF L = 1 THEN
  238.           P1^.Last := NIL        (* Doppelverkettung *)
  239.         ELSE
  240.           P1^.Last := APtr^[Pred(L)];
  241.       END;
  242.     END;
  243.     Liste := APtr^[1];
  244.   END;
  245.  
  246.   PROCEDURE ListeToArray(Liste : Pointer;
  247.                          APtr  : ArrayPtr;
  248.                          ASize : Longint);
  249.   VAR
  250.     L : Index;
  251.     P : SPtr;
  252.   BEGIN
  253.     L := 0;
  254.     P := SPtr(Liste);
  255.  
  256.     WHILE (P <> NIL) AND (L <= Asize) DO BEGIN
  257.       Inc(L);
  258.       APtr^[L] := P;
  259.       P        := P^.Next
  260.     END;
  261.   END;
  262.  
  263.   FUNCTION GetArrayMem(ASize : WORD;
  264.                        VAR P : Pointer) : BYTE;
  265.   BEGIN
  266.     GetArrayMem := Sortokay;
  267.     IF ASize > MaxIndex THEN BEGIN
  268.       GetArrayMem := ToMuchElements;
  269.       Exit;
  270.     END;
  271.     IF MaxAvail >= ASize * SizeOf(Pointer) THEN
  272.       GetMem(P, ASize * SizeOf(Pointer))
  273.     ELSE
  274.       GetArrayMem := MemError;
  275.   END;
  276.  
  277.   PROCEDURE QuickSort(VAR Liste    : Pointer;
  278.                           LTyp     : ListTyp;
  279.                           CompF    : SortFunc;
  280.                           CompPara : WORD);
  281.   VAR
  282.     ArraySize : Index;
  283.     P, Tausch : Pointer;
  284.     APtr      : ArrayPtr;
  285.  
  286.     PROCEDURE QSort(Links, Rechts : WORD);
  287.                    (* Die eigentliche Sortierroutine *)
  288.     VAR
  289.       I, J, M : Index;
  290.     BEGIN
  291.       I := Links;
  292.       J := Rechts;
  293.       M := Rechts;
  294.       REPEAT
  295. (*$IFDEF VER40 *)
  296.         WHILE (CallCompFunc(APtr^[I],
  297.                     APtr^[M], CompPara) = Kleiner) AND
  298.               (I < ArraySize) DO Inc(I);
  299.  
  300.         WHILE (CallCompFunc(APtr^[J],
  301.                     APtr^[M],CompPara) = Groesser) AND
  302.               (J > 1) DO Dec(J);
  303. (*$ELSE *)
  304.         WHILE (CompF(APtr^[I], APtr^[M],
  305.                               CompPara) = Kleiner) AND
  306.               (I < ArraySize) DO Inc(I);
  307.  
  308.         WHILE (CompF(APtr^[J], APtr^[M],
  309.                              CompPara) = Groesser) AND
  310.               (J > 1) DO Dec(J);
  311. (*$ENDIF *)
  312.  
  313.         IF I <= J THEN BEGIN
  314.           Tausch   := APtr^[I];
  315.           APtr^[I] := APtr^[J];
  316.           APtr^[J] := Tausch;
  317.           Inc(I);
  318.           Dec(J);
  319.         END;
  320.       UNTIL I > J;
  321.  
  322.       IF Links  < J THEN QSort(Links, J);
  323.       IF Rechts > I THEN QSort(I, Rechts);
  324.     END;
  325.  
  326.   BEGIN
  327.     ArraySize := ListSize(Liste);
  328.  
  329.     SError    := GetArrayMem(ArraySize,P);
  330.     IF SError <> SortOkay THEN Exit;
  331.  
  332.     APtr := P;
  333.     ListeToArray(Liste, APtr, ArraySize);
  334.  
  335. (*$IFDEF VER40 *)
  336.     InitSortFunc(Compf);
  337. (*$ENDIF *)
  338.     QSort(1, ArraySize);
  339.  
  340.     ArrayToListe(APtr, ArraySize, Liste, LTyp);
  341.     FreeMem(P, ArraySize * SizeOf(Pointer));
  342.   END;
  343.  
  344.   PROCEDURE AustauschSort(VAR Liste    : Pointer;
  345.                               LTyp     : ListTyp;
  346.                               CompF    : SortFunc;
  347.                               CompPara : WORD);
  348.   VAR
  349.     ArraySize : Index;
  350.     P         : Pointer;
  351.     APtr      : ArrayPtr;
  352.     I,J       : Index;
  353.     Hilf      : Pointer;
  354.   BEGIN
  355.     ArraySize := ListSize(Liste);
  356.  
  357.     SError    := GetArrayMem(ArraySize,P);
  358.     IF SError <> SortOkay THEN Exit;
  359.  
  360.     APtr := P;
  361.  
  362.     ListeToArray(Liste, APtr, ArraySize);
  363.                                        (* Umwandlung *)
  364.  
  365.     FOR I := 2 TO ArraySize DO         (* Sortierung *)
  366.       FOR J := ArraySize DOWNTO I DO BEGIN
  367.         IF (CompF(APtr^[Pred(J)], APtr^[J],
  368.                        CompPara) = Groesser) THEN BEGIN
  369.           Hilf           := APtr^[Pred(J)];
  370.           APtr^[Pred(J)] := APtr^[J];
  371.           APtr^[J]       := Hilf;
  372.         END;
  373.       END;
  374.  
  375.     ArrayToListe(APtr, ArraySize, Liste, LTyp);
  376.                                     (* Konvertierung *)
  377.     FreeMem(P, ArraySize * SizeOf(Pointer));
  378.   END;
  379.  
  380.   PROCEDURE EinfuegeSort(VAR Liste    : Pointer;
  381.                              LTyp     : ListTyp;
  382.                              CompF    : SortFunc;
  383.                              CompPara : WORD);
  384.   VAR
  385.     ArraySize : Index;
  386.     P         : Pointer;
  387.     APtr      : ArrayPtr;
  388.     I,J,K     : Index;
  389.     Hilf      : Pointer;
  390.   BEGIN
  391.     ArraySize := ListSize(Liste);
  392.  
  393.     SError    := GetArrayMem(ArraySize,P);
  394.     IF SError <> SortOkay THEN Exit;
  395.  
  396.     APtr := P;
  397.  
  398.     ListeToArray(Liste, APtr, ArraySize);
  399.  
  400.     FOR I := 2 TO ArraySize DO BEGIN
  401.       Hilf := APtr^[I];
  402.       J := 1;
  403.       WHILE (CompF(Hilf, APtr^[J],
  404.                               CompPara) = Groesser) AND
  405.             (J < I) DO Inc(J);
  406.       IF J < I THEN
  407.         FOR K := I DOWNTO Succ(J) DO
  408.           APtr^[K] := APtr^[Pred(K)];
  409.       APtr^[J] := Hilf;
  410.     END;
  411.  
  412.     ArrayToListe(APtr, ArraySize, Liste, LTyp);
  413.     FreeMem(P, ArraySize * SizeOf(Pointer));
  414.   END;
  415.  
  416.   PROCEDURE AuswahlSort(VAR Liste    : Pointer;
  417.                             LTyp     : ListTyp;
  418.                             CompF    : SortFunc;
  419.                             CompPara : WORD);
  420.   VAR
  421.     ArraySize : Index;
  422.     P         : Pointer;
  423.     APtr      : ArrayPtr;
  424.     I,J,M     : Index;
  425.     Hilf      : Pointer;
  426.   BEGIN
  427.     ArraySize := ListSize(Liste);
  428.  
  429.     SError    := GetArrayMem(ArraySize,P);
  430.     IF SError <> SortOkay THEN Exit;
  431.  
  432.     APtr := P;
  433.     ListeToArray(Liste, APtr, ArraySize);
  434.  
  435.     FOR I := 1 TO Pred(ArraySize) DO BEGIN
  436.       M   := I;
  437.       FOR J := Succ(I) TO ArraySize DO
  438.  
  439.         IF (CompF(APtr^[M], APtr^[J],
  440.                      CompPara) = Groesser) THEN M := J;
  441.       Hilf     := APtr^[I];
  442.       APtr^[I] := APtr^[M];
  443.       APtr^[M] := Hilf;
  444.     END;
  445.  
  446.     ArrayToListe(APtr, ArraySize, Liste, LTyp);
  447.     FreeMem(P, ArraySize * SizeOf(Pointer));
  448.   END;
  449.  
  450.   PROCEDURE ArraySort(APtr     : Pointer;
  451.                       ASize    : WORD;
  452.                       ElSize   : WORD;
  453.                       CompF    : SortFunc;
  454.                       CompPara : WORD);
  455.   (* Routine für das Sortieren beliebiger Arrays     *)
  456.   (* Algorithmus : Quicksort                         *)
  457.   VAR
  458.     Tausch     : Pointer;
  459.     ASeg, AOfs : WORD;
  460.  
  461.     PROCEDURE QSort(Links, Rechts : WORD);
  462.     VAR
  463.       I, J, M : Index;
  464.     BEGIN
  465.       I := Links;
  466.       J := Rechts;
  467.       M := Rechts;
  468.       REPEAT
  469. (*$IFDEF VER40 *)
  470.         WHILE (CallCompFunc(Ptr(ASeg,
  471.                AOfs+Pred(I)*ElSize),
  472.           Ptr(Aseg, AOfs+Pred(M)*ElSize),
  473.                                CompPara) = Kleiner) AND
  474.              (I < ASize) DO Inc(I);
  475.  
  476.         WHILE (CallCompFunc(Ptr(ASeg,
  477.                AOfs+Pred(J)*ElSize),
  478.                Ptr(Aseg,AOfs+Pred(M)*ElSize),
  479.                    CompPara) = Groesser) AND
  480.               (J > 1) DO Dec(J);
  481. (*$ELSE *)
  482.         WHILE (CompF(Ptr(ASeg, AOfs+Pred(I)*ElSize),
  483.               Ptr(Aseg, AOfs+Pred(M)*ElSize),
  484.               CompPara) = Kleiner) AND
  485.               (I < ASize) DO Inc(I);
  486.  
  487.         WHILE (CompF(Ptr(ASeg, AOfs+Pred(J)*ElSize),
  488.               Ptr(Aseg, AOfs+Pred(M)*ElSize),
  489.               CompPara) = Groesser) AND
  490.               (J > 1) DO Dec(J);
  491. (*$ENDIF *)
  492.  
  493.       IF I <= J THEN BEGIN
  494.         Move(Mem[ASeg:AOfs+Pred(I) * ElSize],
  495.              Tausch^,ElSize);
  496.         Move(Mem[Aseg:AOfs+Pred(J) * ElSize],
  497.              Mem[Aseg:AOfs+Pred(I) * ElSize], ElSize);
  498.         Move(Tausch^,
  499.              Mem[ASeg:AOfs+Pred(J) * ElSize], ElSize);
  500.         Inc(I);
  501.         Dec(J);
  502.       END;
  503.     UNTIL I > J;
  504.     IF Links  < J THEN QSort(Links, J);
  505.     IF Rechts > I Then QSort(I, Rechts);
  506.   END;
  507.  
  508. BEGIN
  509.   SError := GetArrayMem(ElSize, Tausch);
  510.   IF SError <> SortOkay THEN Exit;
  511.  
  512.   ASeg  := Seg(APtr^);
  513.   AOfs  := Ofs(APtr^);
  514.  
  515. (*$IFDEF VER40 *)
  516.   InitSortFunc(Compf);
  517. (*$ENDIF *)
  518.  
  519.   QSort(1,ASize);
  520.  
  521. END;
  522.  
  523. BEGIN
  524. END.
  525. (* ------------------------------------------------- *)
  526. (*              Ende von HRS.PAS                     *)
  527.