SOURCE FILE: qsort.pas


(* This is one of the quicksort's from the fourth edition of
   "Pascal Plus Data Structures" by Dale and Lily. *)

(*********************************************************)

PROCEDURE Split
  (VAR Info       : ArrayType;
   First          : Integer;
   Last           : Integer;
   VAR SplitPoint : IndexType);

  (* Choose SplitVal and rearrange Info so that:              *)
  (* Info[First]..Info[SplitPoint - 1] <= SplitVal and        *)
  (* Info[SplitPoint] = SplitVal and                          *)
  (* Info[SplitPoint + 1] .. Info[Last] > SplitVal.           *)

VAR
  SplitVal      : ListElementType; (* value on which to split *)
  SaveFirst     : IndexType; (* original value of First       *)
  OnCorrectSide : Boolean;

BEGIN (* Split *)

  (* SplitVal is chosen from the First array slot. *)
  SplitVal := Info[First];

  (* Set up for split loop. *)
  SaveFirst := First;
  First := First + 1;

  (* Loop invariant: elements to the left of First are *)
  (* less than or equal to SplitVal; elements to the   *)
  (* right of Last are greater than SplitVal.          *)
  REPEAT

    OnCorrectSide := True;
    WHILE OnCorrectSide DO
      Case Compare (Info[First], SplitVal) OF

        Greater  : (* Info[First] is on the wrong side
                      of SplitVal *)
                   OnCorrectSide := False;
        Less,
        Equal    : BEGIN
                     First := First + 1;
                     OnCorrectSide := First <= Last
                     (* First crossed Last? *)
                   END;
      END;  (* CASE *)
    OnCorrectSide := First <= Last;  (* First crossed Last? *)
    WHILE OnCorrectSide DO
      CASE Compare (Info[Last], SplitVal) OF
        Less,     (* Info[Last] is on the wrong side of splitVal *)
        Equal   : OnCorrectSide := False;
        Greater : BEGIN
                    Last := Last - 1;
                    OnCorrectSide := First <= Last
                  END;
      END;   (* CASE *)
    (* If on wrong side, Swap (Info[First], Info[Last]) *)
    (* and update First and Last,                       *)
    IF First < Last
      THEN
        BEGIN
          Swap (Info[First], Info[Last]);
          First := First + 1;
          Last := Last - 1
        END      (* IF *)

  UNTIL First > Last;

  (* Set SplitPoint to place where the halves meet. *)
  SplitPoint := Last;
  (* Swap SplitVal with element at SplitPoint. *)
  Swap (Info[SaveFirst], Info[SplitPoint])

END; (* Split *)

(*********************************************************)

PROCEDURE QuickSort
  (VAR Info : ArrayType;
   First    : Integer;
   Last     : Integer);

VAR
  SplitPoint : IndexType;

BEGIN  (* QuickSort *)

  IF First < Last  (* General Case *)
    THEN
      BEGIN

        (* Procedure Split chooses the splitting value and *)
        (* rearranges the array so that:                   *)
        (* Info[First] .. Info[SplitPoint - 1] <= SplitVal *)
        (* Info[SplitPoint] = SplitVal                     *)
        (* Info[SplitPoint + 1] .. Info[Last] > SplitVal.  *)
        Split (Info, First, Last, SplitPoint);

        (* Sort the left "half." *)
        QuickSort (Info, First, SplitPoint - 1);

        (* Sort the right "half." *)
        QuickSort (Info, SplitPoint + 1, Last)

      END   (* IF First < Last *)

   (* ELSE Base Case: Do nothing. *)
END;  (* QuickSort *)

(***************************************************************)