-- Copyright 1994 Grady Booch.
-- Copyright 2001-2002 Simon Wright <simon@pushface.org>
-- This package is free software; you can redistribute it and/or
-- modify it under terms of the GNU General Public License as
-- published by the Free Software Foundation; either version 2, or
-- (at your option) any later version. This package is distributed in
-- the hope that it will be useful, but WITHOUT ANY WARRANTY; without
-- even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-- PARTICULAR PURPOSE. See the GNU General Public License for more
-- details. You should have received a copy of the GNU General Public
-- License distributed with this package; see file COPYING. If not,
-- write to the Free Software Foundation, 59 Temple Place - Suite
-- 330, Boston, MA 02111-1307, USA.
-- As a special exception, if other files instantiate generics from
-- this unit, or you link this unit with other files to produce an
-- executable, this unit does not by itself cause the resulting
-- executable to be covered by the GNU General Public License. This
-- exception does not however invalidate any other reasons why the
-- executable file might be covered by the GNU Public License.
-- $RCSfile: bc-containers-quicksort.adb,v $
-- $Revision: 1.5.2.2 $
-- $Date: 2002/12/26 11:43:52 $
-- $Author: simon $
-- The Sedgewick algorithm is from "Algorithms", Robert Sedgewick,
-- Addison-Wesley 1983, with adjustments to obviate Constraint_Error.
procedure BC.Containers.Quicksort (C : in out Container) is
procedure Booch (C : in out Containers.Container'Class;
L, R : Natural);
procedure Sedgewick (C : in out Containers.Container'Class;
L, R : Natural);
procedure Sedgewick (C : in out Containers.Container'Class;
L, R : Natural) is
V : Item;
I : Natural;
J : Positive;
procedure Swap (A, B : Positive);
pragma Inline (Swap);
procedure Swap (A, B : Positive) is
Temp : constant Item := Item_At (C, A).all;
begin
Item_At (C, A).all := Item_At (C, B).all;
Item_At (C, B).all := Temp;
end Swap;
begin
if R > L then
V := Item_At (C, R).all;
I := L - 1;
J := R;
loop
loop
I := I + 1;
exit when I = R or else V < Item_At (C, I).all;
end loop;
loop
J := J - 1;
exit when J = L
or else Item_At (C, J).all = V
or else Item_At (C, J).all < V;
end loop;
Swap (I, J);
exit when J <= I;
end loop;
Swap (J, I);
Swap (I, R);
Sedgewick (C, L, I - 1);
Sedgewick (C, I + 1, R);
end if;
end Sedgewick;
procedure Booch (C : in out Containers.Container'Class;
L, R : Natural) is
procedure Swap (A, B : Positive);
pragma Inline (Swap);
procedure Swap (A, B : Positive) is
Temp : constant Item := Item_At (C, A).all;
begin
Item_At (C, A).all := Item_At (C, B).all;
Item_At (C, B).all := Temp;
end Swap;
begin
if R > L + 1 then
declare
M : constant Positive := (L + R) / 2;
Pivot : constant Item := Item_At (C, M).all;
T : Positive := R;
B : Positive := L + 1;
Flag : Boolean := True;
begin
-- park the pivot item at the left
Swap (M, L);
-- this loop I do _not_ understand
while B <= T and then Flag loop
if Pivot < Item_At (C, B).all then
Flag := False;
while T >= B and then not Flag loop
if Item_At (C, T).all < Pivot then
Swap (B, T);
Flag := True;
end if;
T := T - 1;
end loop;
end if;
if Flag then
B := B + 1;
else
T := B - 1;
end if;
end loop;
-- put the pivot item in its final position
Swap (L, T);
-- sort the left part, if it's longer than one element
if L < T - 1 then
Booch (C, L, T - 1);
end if;
-- sort the right part, if it's longer than one element
if T + 1 < R then
Booch (C, T + 1, R);
end if;
end;
elsif R > L and then Item_At (C, R).all < Item_At (C, L).all then
-- length is 2, in the wrong order
Swap (L, R);
end if;
end Booch;
begin
Booch (C, 1, Length (C));
exception
when Should_Have_Been_Overridden => raise Sort_Error;
end BC.Containers.Quicksort;
syntax highlighted by Code2HTML, v. 0.9.1