[M3devel] Dual Pivot Quicksort problem

Martin Bishop mbishop at esoteriq.org
Sat Sep 12 02:58:04 CEST 2009


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:

MODULE DualPivot;

IMPORT Insertion, Fmt;

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 := left - right;
    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);
    END;
   
    IF m1 <= left THEN
      m1 := left + 1;
    END;

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

    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 + 1);
      ELSIF arr[k] > piv2 THEN
        WHILE (k < great) AND (arr[great] > piv2) DO
          DEC(great);
        END;
        Swap(arr, k, great - 1);
       
        IF arr[k] < piv1 THEN
          Swap(arr, k, less + 1);
        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 + 1);
        ELSIF arr[k] = piv2 THEN
          Swap(arr, k, great - 1);
         
          IF arr[k] = piv1 THEN
            Swap(arr, k, less + 1);
          END;
        END;
      END;
    END;

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

BEGIN
END DualPivot.

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