[M3devel] subrange value not constant?

Mika Nystrom mika at async.caltech.edu
Thu May 21 20:39:57 CEST 2009


Martin Bishop writes:
>Hmm, good point about count.  Originally I did initialize to 0, but in 
>the process of trying to get it to work, I must have removed it.
>
>As for min and max, yes the point of the Counting Sort 
>(http://en.wikipedia.org/wiki/Counting_sort) is that min and max are known.
>
>Thanks for the help :)

Well what I mean is this.  Assume you know that counting sort is
appropriate for your data, i.e., that n + k <= n log n for the data
in question (using Wikipedia's notation).

There are two approaches I can think of for implementing the sort.

1. Figure out min and max before calling Sort, by a linear scan, or some
other mechanism.  If this mechanism adds any code at all, it's likely to
add O(n) runtime to the algorithm (because you are making it look at
every element before it goes in).

2. Dispense with min and max and instead generate these dynamically within
the sort.  Initialize them to the first element, and re-allocate the
array when you see any element outside the current range.  This approach
also has O(n) (amortized) cost.

So you'd do, say,

PROCEDURE Sort(VAR a : ARRAY OF INTEGER) =

  PROCEDURE ReLimit(newmin, newmax : INTEGER) =
    BEGIN
      WITH newcount = NEW(REF ARRAY OF CARDINAL, newmax - newmin + 1) DO
        FOR i := FIRST(newcount^) TO min-newmin-1 DO newcount[i] := 0 END;
        FOR i := newmax-max TO LAST(newcount^) DO newcount[i] := 0 END;
        SUBARRAY(newcount^, min-newmin, max-min+1) := count^;
      END;
      count := newcount; min := newmin; max := newmax
    END ReLimit;

  PROCEDURE Tally(v : INTEGER) =
    CONST GrowFactor = 2;
    BEGIN 
      IF    v < min THEN ReLimit(min-(min-v)*GrowFactor, max) 
      ELSIF v > max THEN ReLimit(min, max+(v-max)*GrowFactor)
      END;
      INC(count[v-min])
    END Tally;

  PROCEDURE Initialize() =
    BEGIN
      min := a[0]; max := a[0]; 
      count := NEW(REF ARRAY OF CARDINAL, 1); 
    END Initialize;

  PROCEDURE Reconstruct() =
    VAR ai := FIRST(a);
    BEGIN
      FOR i := FIRST(count^) TO LAST(count^) DO
        WHILE count[i] > 0 DO
          a[ai] := i+min; 
          DEC(count[i]); INC(ai)
        END
      END
    END Reconstruct;

  VAR min, max : INTEGER;
      count : REF ARRAY OF INTEGER;
  BEGIN
    Initialize();

    FOR i := FIRST(a) TO LAST(a) DO
      Tally(a[i])
    END;

    Reconstruct()
  END Sort;

The asymptotic runtime of this version is the same as yours and it
encapsulates all the min, max knowledge, giving a simpler interface,
and it usually means you can remove some min, max code from the
caller.

Modula-3 is really good for this sort of coding.  I find that the
extra effort of simplifying interfaces and making sure the code
works for any input is paid off handsomely and very quickly...

As it says in the Algol-60 report, the code above "has not been run
on a computer".

     Mika
     



More information about the M3devel mailing list