unit Qsort; {TQSort by Mike Junkin 10/19/95. DoQSort routine adapted from Peter Szymiczek's QSort procedure which was presented in issue#8 of The Unofficial Delphi Newsletter.} interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs; type TSwapEvent = procedure (Sender : TObject; e1,e2 : word) of Object; TCompareEvent = procedure (Sender: TObject; e1,e2 : word; var Action : integer) of Object; TQSort = class(TComponent) private FCompare : TCompareEvent; FSwap : TSwapEvent; public procedure DoQSort(Sender: TObject; uNElem: word); published property Compare : TCompareEvent read FCompare write FCompare; property Swap : TSwapEvent read FSwap write FSwap; end; procedure Register; implementation procedure Register; begin RegisterComponents('Mikes', [TQSort]); end; procedure TQSort.DoQSort(Sender: TObject; uNElem: word); { uNElem - number of elements to sort } procedure qSortHelp(pivotP: word; nElem: word); label TailRecursion, qBreak; var leftP, rightP, pivotEnd, pivotTemp, leftTemp: word; lNum: word; retval: integer; begin retval := 0; TailRecursion: if (nElem <= 2) then begin if (nElem = 2) then begin rightP := pivotP +1; FCompare(Sender,pivotP,rightP,retval); if (retval > 0) then Fswap(Sender,pivotP,rightP); end; exit; end; rightP := (nElem -1) + pivotP; leftP := (nElem shr 1) + pivotP; { sort pivot, left, and right elements for "median of 3" } FCompare(Sender,leftP,rightP,retval); if (retval > 0) then Fswap(Sender,leftP, rightP); FCompare(Sender,leftP,pivotP,retval); if (retval > 0) then Fswap(Sender,leftP, pivotP) else begin FCompare(Sender,pivotP,rightP,retval); if retval > 0 then Fswap(Sender,pivotP, rightP); end; if (nElem = 3) then begin Fswap(Sender,pivotP, leftP); exit; end; { now for the classic Horae algorithm } pivotEnd := pivotP + 1; leftP := pivotEnd; repeat FCompare(Sender,leftP, pivotP,retval); while (retval <= 0) do begin if (retval = 0) then begin Fswap(Sender,leftP, pivotEnd); Inc(pivotEnd); end; if (leftP < rightP) then Inc(leftP) else goto qBreak; FCompare(Sender,leftP, pivotP,retval); end; {while} while (leftP < rightP) do begin FCompare(Sender,pivotP, rightP,retval); if (retval < 0) then Dec(rightP) else begin FSwap(Sender,leftP, rightP); if (retval <> 0) then begin Inc(leftP); Dec(rightP); end; break; end; end; {while} until (leftP >= rightP); qBreak: FCompare(Sender,leftP,pivotP,retval); if (retval <= 0) then Inc(leftP); leftTemp := leftP -1; pivotTemp := pivotP; while ((pivotTemp < pivotEnd) and (leftTemp >= pivotEnd)) do begin Fswap(Sender,pivotTemp, leftTemp); Inc(pivotTemp); Dec(leftTemp); end; {while} lNum := (leftP - pivotEnd); nElem := ((nElem + pivotP) -leftP); if (nElem < lNum) then begin qSortHelp(leftP, nElem); nElem := lNum; end else begin qSortHelp(pivotP, lNum); pivotP := leftP; end; goto TailRecursion; end; {qSortHelp } begin if Assigned(FCompare) and Assigned(FSwap) then begin if (uNElem < 2) then exit; { nothing to sort } qSortHelp(1, uNElem); end; end; { QSort } end. { demo } unit Unit1; interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, Grids, Qsort, StdCtrls; type TForm1 = class(TForm) QSort1: TQSort; StringGrid1: TStringGrid; Button1: TButton; procedure FormCreate(Sender: TObject); procedure QSort1Compare(Sender: TObject; e1, e2: Word; var Action: Integer); procedure QSort1Swap(Sender: TObject; e1, e2: Word); procedure Button1Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin with StringGrid1 do begin Cells[1,1] := 'the'; Cells[1,2] := 'brown'; Cells[1,3] := 'dog'; Cells[1,4] := 'bit'; Cells[1,5] := 'me'; end; end; procedure TForm1.QSort1Compare(Sender: TObject; e1, e2: Word; var Action: Integer); begin with Sender as TStringGrid do begin if (Cells[1, e1] < Cells[1, e2]) then Action := -1 else if (Cells[1, e1] > Cells[1, e2]) then Action := 1 else Action := 0; end; {with} end; procedure TForm1.QSort1Swap(Sender: TObject; e1, e2: Word); var s: string[63]; { must be large enough to contain the longest string in the grid } i: integer; begin with Sender as TStringGrid do for i := 0 to ColCount -1 do begin s := Cells[i, e1]; Cells[i, e1] := Cells[i, e2]; Cells[i, e2] := s; end; {for} end; procedure TForm1.Button1Click(Sender: TObject); begin QSort1.DoQSort(StringGrid1,STringGrid1.RowCount-1); end; end.