Unit SORTER; INTERFACE TYPE PtrArray = ARRAY[1..1] OF Pointer; TCompareFunction = FUNCTION (VAR AnArray; Item1, Item2 : LongInt) : Integer; { A TCompareFunction must return: } { 1 if the Item1 > Item2 } { 0 if the Item1 = Item2 } { -1 if the Item1 < Item2 } TSwapProcedure = PROCEDURE (VAR AnArray; Item1, Item2 : LongInt); PROCEDURE CombSort (VAR AnArray; Min, Max : LongInt; Compare : TCompareFunction; Swap : TSwapProcedure); { Compare Procedures - Must write your own Compare for pointer variables. } { This allows one sort routine to be used on any array. } FUNCTION CompareChars (VAR AnArray; Item1, Item2 : LongInt) : Integer; FAR; FUNCTION CompareInts (VAR AnArray; Item1, Item2 : LongInt) : Integer; FAR; FUNCTION CompareLongInts (VAR AnArray; Item1, Item2 : LongInt) : Integer; FAR; FUNCTION CompareReals (VAR AnArray; Item1, Item2 : LongInt) : Integer; FAR; FUNCTION CompareStrs (VAR AnArray; Item1, Item2 : LongInt) : Integer; FAR; { Swap procedures to be used in any sorting routine. } { This allows one sorting routine to be on any array. } PROCEDURE SwapChars (VAR AnArray; A, B : LongInt); FAR; PROCEDURE SwapInts (VAR AnArray; A, B : LongInt); FAR; PROCEDURE SwapLongInts (VAR AnArray; A, B : LongInt); FAR; PROCEDURE SwapPtrs (VAR AnArray; A, B : LongInt); FAR; PROCEDURE SwapReals (VAR AnArray; A, B : LongInt); FAR; PROCEDURE SwapStrs (VAR AnArray; A, B : LongInt); FAR; {****************************************************************************} IMPLEMENTATION {****************************************************************************} TYPE CharArray = ARRAY[1..1] OF Char; IntArray = ARRAY[1..1] OF Integer; LongIntArray = ARRAY[1..1] OF LongInt; RealArray = ARRAY[1..1] OF Real; StrArray = ARRAY[1..1] OF String; {****************************************************************************} { } { Local Procedures and Functions } { } {****************************************************************************} PROCEDURE AdjustArrayIndexes (VAR Min, Max : LongInt); { Adjusts array indexes to a one-based array. } VAR Fudge : LongInt; BEGIN Fudge := 1 - Min; Inc(Min,Fudge); Inc(Max,Fudge); END; {****************************************************************************} { } { Global Procedures and Functions } { } {**************************************************************************** }PROCEDURE CombSort (VAR AnArray; Min, Max : LongInt; Compare : TCompareFunction; Swap : TSwapProcedure); { The combsort is an optimised version of the bubble sort. It uses a } { decreasing gap in order to compare values of more than one element } { apart. By decreasing the gap the array is gradually "combed" into } { order ... like combing your hair. First you get rid of the large } { tangles, then the smaller ones ... } { } { There are a few particular things about the combsort. Firstly, the } { optimal shrink factor is 1.3 (worked out through a process of } { exhaustion by the guys at BYTE magazine). Secondly, by never } { having a gap of 9 or 10, but always using 11, the sort is faster. } { } { This sort approximates an n log n sort - it's faster than any } { other sort I've seen except the quicksort (and it beats that too } { sometimes ... have you ever seen a quicksort become an (n-1)^2 } { sort ... ?). The combsort does not slow down under *any* } { circumstances. In fact, on partially sorted lists (including } { *reverse* sorted lists) it speeds up. } { } { More information in the April 1991 BYTE magazine. } CONST ShrinkFactor = 1.3; VAR Gap, i : LongInt; Finished : Boolean; BEGIN AdjustArrayIndexes(Min,Max); Gap := Round(Max/ShrinkFactor); REPEAT Finished := TRUE; Gap := Trunc(Gap/ShrinkFactor); IF Gap < 1 THEN Gap := 1 ELSE IF (Gap = 9) OR (Gap = 10) THEN Gap := 11; FOR i := Min TO (Max - Gap) DO IF Compare(AnArray,i,i+Gap) = 1 THEN BEGIN Swap(AnArray,i,i+Gap); Finished := False; END; UNTIL ((Gap = 1) AND Finished); END; {**************************************************************************** }{ }{ Compare Procedures }{ }{********************************** ******************************************}FUNCTION CompareChars (VAR AnArray; Item1, Item2 : LongInt) : Integer;BEGIN IF CharArray(AnArray)[Item1] < CharArray(AnArray)[Item2] THEN CompareChars := -1 ELSE IF CharArray(AnArray)[Item1] = CharArray(AnArray)[Item2] THEN CompareChars := 0 ELSE CompareChars := 1; END; {*****************************************************************************} FUNCTION CompareInts (VAR AnArray; Item1, Item2 : LongInt) : Integer; BEGIN IF IntArray(AnArray)[Item1] < IntArray(AnArray)[Item2] THEN CompareInts := -1 ELSE IF IntArray(AnArray)[Item1] = IntArray(AnArray)[Item2] THEN CompareInts := 0 ELSE CompareInts := 1; END; {*****************************************************************************} FUNCTION CompareLongInts (VAR AnArray; Item1, Item2 : LongInt) : Integer; BEGIN IF LongIntArray(AnArray)[Item1] < LongIntArray(AnArray)[Item2] THEN CompareLongInts := -1 ELSE IF LongIntArray(AnArray)[Item1] = LongIntArray(AnArray)[Item2] THEN CompareLongInts := 0 ELSE CompareLongInts := 1; END; {*****************************************************************************} FUNCTION CompareReals (VAR AnArray; Item1, Item2 : LongInt) : Integer; BEGIN IF RealArray(AnArray)[Item1] < RealArray(AnArray)[Item2] THEN CompareReals := -1 ELSE IF RealArray(AnArray)[Item1] = RealArray(AnArray)[Item2] THEN CompareReals := 0 ELSE CompareReals := 1; END; {*****************************************************************************} FUNCTION CompareStrs (VAR AnArray; Item1, Item2 : LongInt) : Integer; BEGIN IF StrArray(AnArray)[Item1] < StrArray(AnArray)[Item2] THEN CompareStrs := -1 ELSE IF StrArray(AnArray)[Item1] = StrArray(AnArray)[Item2] THEN CompareStrs := 0 ELSE CompareStrs := 1; END; {****************************************************************************} { } { Move Procedures } { } {****************************************************************************} PROCEDURE MoveChar (VAR AnArray; Item : LongInt; VAR Hold); BEGIN Char(Hold) := CharArray(AnArray)[Item]; END; {****************************************************************************} { } { MoveBack Procedures } { } {****************************************************************************} PROCEDURE MoveBackChar (VAR AnArray; Item : LongInt; VAR Hold); BEGIN CharArray(AnArray)[Item] := Char(Hold); END; {****************************************************************************} { } { Swap Procedures } { } {****************************************************************************} PROCEDURE SwapChars (VAR AnArray; A, B : LongInt); VAR Item : Char; BEGIN Item := CharArray(AnArray)[A]; CharArray(AnArray)[A] := CharArray(AnArray)[B]; CharArray(AnArray)[B] := Item; END; {*****************************************************************************} PROCEDURE SwapInts (VAR AnArray; A, B : LongInt); VAR Item : Integer; BEGIN Item := IntArray(AnArray)[A]; IntArray(AnArray)[A] := IntArray(AnArray)[B]; IntArray(AnArray)[B] := Item; END; {*****************************************************************************} PROCEDURE SwapLongInts (VAR AnArray; A, B : LongInt); VAR Item : LongInt; BEGIN Item := LongIntArray(AnArray)[A]; LongIntArray(AnArray)[A] := LongIntArray(AnArray)[B]; LongIntArray(AnArray)[B] := Item; END; {****************************************************************************} PROCEDURE SwapPtrs (VAR AnArray; A, B : LongInt); VAR Item : Pointer; BEGIN Item := PtrArray(AnArray)[A]; PtrArray(AnArray)[A] := PtrArray(AnArray)[B]; PtrArray(AnArray)[B] := Item; END; {****************************************************************************} PROCEDURE SwapReals (VAR AnArray; A, B : LongInt); VAR Item : Real; BEGIN Item := RealArray(AnArray)[A]; RealArray(AnArray)[A] := RealArray(AnArray)[B]; RealArray(AnArray)[B] := Item; END; {*****************************************************************************} PROCEDURE SwapStrs (VAR AnArray; A, B : LongInt); VAR Item : String; BEGIN Item := StrArray(AnArray)[A]; StrArray(AnArray)[A] := StrArray(AnArray)[B]; StrArray(AnArray)[B] := Item; END; {*****************************************************************************} BEGIN END.