[M3devel] Dual Pivot Quicksort problem

Martin Bishop mbishop at esoteriq.org
Sat Sep 12 06:01:05 CEST 2009


Edited it some more, lots of silly mistakes in that old code.  Now it 
almost works...it sorts the array sometimes, but other times gives me a 
bounds error.  Any idea now?

MODULE DualPivot;

IMPORT Insertion, Fmt, IO;

PROCEDURE Sort(VAR arr: ARRAY OF INTEGER) =
  BEGIN
    SortFromTo(arr, 0, NUMBER(arr));
  END Sort;

PROCEDURE SortFromTo(VAR arr: ARRAY OF INTEGER; from, to: INTEGER) =
  BEGIN
    RangeCheck(NUMBER(arr), from, to);
    DualPivotSort(arr, from, to - 1, 3);
  END SortFromTo;

PROCEDURE RangeCheck(len, from, to: INTEGER) RAISES {BadArgument, 
IndexOutOfRange} =
  BEGIN
    IF from > to THEN
      RAISE BadArgument(Fmt.Int(from) & " > " & Fmt.Int(to) & "\n");
    END;
    IF from < 0 THEN
      RAISE IndexOutOfRange("from");
    END;
    IF to > len THEN
      RAISE IndexOutOfRange("to");
    END;
  END RangeCheck;

PROCEDURE Swap(VAR arr: ARRAY OF INTEGER; i, j: INTEGER) =
  VAR temp := arr[i];
  BEGIN
    arr[i] := arr[j];
    arr[j] := temp;
  END Swap;

PROCEDURE DualPivotSort(VAR arr: ARRAY OF INTEGER; left, right, div: 
INTEGER) =
  VAR
    len := right - left;
    third := len DIV div;
    m1 := left + third;
    m2 := right - third;
    piv1: INTEGER;
    piv2: INTEGER;
    less := left + 1;
    great := right - 1;
    dist: INTEGER;

  BEGIN
    IF len < 27 THEN
      Insertion.Sort(arr);
      RETURN;
    END;

    IF m1 <= left THEN
      m1 := left + 1;
    END;

    IF m2 >= right THEN
      m2 := right - 1;
    END;

    IO.Put("DEBUG: m1 = " & Fmt.Int(m1) & " m2 = " & Fmt.Int(m2) &
      " left = " & Fmt.Int(left) & " right = " & Fmt.Int(right) & "\n");
    IO.Put("DEBUG: len = " & Fmt.Int(len) & " third = " & Fmt.Int(third) 
& "\n");
    IO.Put("***\n");

    IF arr[m1] < arr[m2] THEN
      Swap(arr, m1, left);
      Swap(arr, m2, right);
    ELSE
      Swap(arr, m1, right);
      Swap(arr, m2, left);
    END;

    piv1 := arr[left];
    piv2 := arr[right];
   
    FOR k := less TO great DO
      IF arr[k] < piv1 THEN
        Swap(arr, k, less);
        INC(less);
      ELSIF arr[k] > piv2 THEN
        WHILE (k < great) AND (arr[great] > piv2) DO
          DEC(great);
        END;
        Swap(arr, k, great);
        DEC(great);
       
        IF arr[k] < piv1 THEN
          Swap(arr, k, less);
          INC(less);
        END;
      END;
    END;

    dist := great - less;

    IF dist < 13 THEN
      INC(div);
    END;

    Swap(arr, less - 1, left);
    Swap(arr, great + 1, right);
   
    DualPivotSort(arr, left, less - 2, div);
    DualPivotSort(arr, great + 2, right, div);
   
    IF (dist > len - 13) AND (piv1 # piv2) THEN
      FOR k := less TO great DO
        IF arr[k] = piv1 THEN
          Swap(arr, k, less);
          INC(less);
        ELSIF arr[k] = piv2 THEN
          Swap(arr, k, great);
          DEC(great);
         
          IF arr[k] = piv1 THEN
            Swap(arr, k, less);
            INC(less);
          END;
        END;
      END;
    END;

    IF piv1 < piv2 THEN
      DualPivotSort(arr, less, great, div);
    END;
  END DualPivotSort;

BEGIN
END DualPivot.

Martin Bishop wrote:
> I saw a post on reddit about a Dual Pivot Quicksort, and I translated 
> the code from Java to Modula-3.  I have it all translated, and it 
> builds, but I am having boundary issues.  Somewhere on the second 
> pass, the variable m2 is getting the value -2.  Here's the code:
>
> ...

> Right now when I try to run I get:
>
> ***
> *** runtime error:
> ***    An array subscript was out of range.
> ***    file "../DualPivot.m3", line 61
> ***
>
> Line 61 is:  IF arr[m1] < arr[m2] THEN
>
> Anyone see what is happening? It's probably off by 1 (or more) errors, 
> but I don't see them.
>
>




More information about the M3devel mailing list