3

I've come up with the following but it predictably doesn't work.

var t = new Array(a.length);
var r = 4;
var b = 64;

var count = new Array(1<<r);
var pref = new Array(1<<r);

var groups = Math.ceil(b / r);

var mask = (1 << r) - 1;

var shift = 0;
for(var c = 0; c < groups; c++)
{
    shift += r;

    for(var j = 0; j < count.length; j++)
    {
        count[j] = 0;
    }

    for(var i = 0; i < a.length; i++)
    {
        count[ (a[i] >> shift) & mask ]++;
    }

    pref[0] = 0;

    for(var i = 0; i < count.length; i++)
    {
        pref[i] = pref[i-1] + count[i-1];
    }

    for(var i = 0; i < a.length; i++)
    {
        t[ pref[ (a[i] >> shift) & mask ]++ ] = a[i];
    }

    for(var i = 0; i < a.length; i++)
    {
        a[i] = t[i];
    }
    // a is sorted?
}
Josh K
  • 26,152
  • 19
  • 79
  • 130
  • `a` holds the input array of integers? Why are you not zeroing `count`, `pref`, and `groups`? Arrays in JS, even when created via `new Array(length)` start with undefined content, and `undefined + 0` is `NaN`. – Mike Samuel Sep 28 '10 at 21:10
  • @Mike: First, I'm not even quite sure how this sort is *supposed* to work, hence I'm not sure what's broken. `count` is already zeroed out, `pref` is initialized before it's used, and `groups` is not an array. – Josh K Sep 28 '10 at 21:13
  • A *radix sort* sorts by looking at pieces of the sort key, pieces small enough such that all possible values for a piece can describe a manageable number of discrete lists. Imagine sorting your CD collection: first make piles by artist name's second letter, then go through the piles A - Z and make new piles by first letter. When you pick up the piles A - Z again and line them up left-to-right on a shelf, they're sorted! – Pointy Sep 28 '10 at 21:24
  • can you provide sample input and output? – lincolnk Sep 28 '10 at 21:37
  • Well one problem is that "b" appears to represent the size of each integer in bits, and that's going to be the wrong value for Javascript. Javascript integers are only 32 bits (or 31). – Pointy Sep 28 '10 at 21:45

2 Answers2

6

This loop does basically the same thing, in a more Javascript-y way:

for (var div = 1, radix = 16; div < 65536 * 65536; div *= radix) {
  var piles = [];

  for (var i = 0; i < a.length; ++i) {
    var p = Math.floor(a[i] / div) % radix;
    (piles[p] || (piles[p] = [])).push(a[i]);
  }

  for (var i = 0, ai = 0; i < piles.length; ++i) {
    if (!piles[i]) continue;
    for (var pi = 0; pi < piles[i].length; ++pi)
      a[ai++] = piles[i][pi];
  }
}

Instead of doing it like a C programmer might, this loop builds a list of lists, one list for each possible 4-bit value. I avoid bit-shift operators because this is Javascript and while they do work, things get funny when numbers get large.

Starting with the low 4 bits of each value in "a", the code copies that element of "a" to the end of one of the "piles", that being the one corresponding to the 4-bit value. It then gathers up the piles and rebuilds "a" starting from all of the values whose low 4 bits were 0, then 1, etc. (Clearly there'll be some gaps, so those are skipped.) At the end of each iteration of the overall loop, the divisor is multiplied by the radix, so that the next set of 4 bits will be examined.

Once the divisor has exhausted the available range of integers, it's done.

Note that this will only work for positive numbers. Doing this with negative numbers gets a little weird; it might be easier to strip out the negative numbers into a separate array, flip the sign, sort, then reverse. Sort the positive numbers, and then finally glue the reversed negative numbers (flipping the signs again) to the front of the sorted positive numbers.

Pointy
  • 371,531
  • 55
  • 528
  • 584
  • 1
    This works, and I will pull it apart to see if I can wrap my head around it. I would like to implement this sort in some of my code, do I have your permission to do so? – Josh K Sep 29 '10 at 01:06
  • Sure; this is pretty common stuff. I enjoyed your question because I've been trying to get one of my kids excited about the prospect of radix sorting my old LP collection :-) – Pointy Sep 29 '10 at 03:14
0

this

for(var i = 0; i < count.length; i++) 
{ 
    pref[i] = pref[i-1] + count[i-1]; 
} 

is a problem because on the first iteration, i is zero and so pref[ 0 - 1 ] is not going to work very well.

I don't have a reference for radix sorts handy to determine what you should actually be doing here.

lincolnk
  • 10,642
  • 3
  • 36
  • 56
  • The "pref" array is intended to hold the count of values for each radix bucket. If I were doing it in Javascript, I wouldn't do it that way at all; it's like a transcribed C program. – Pointy Sep 28 '10 at 21:53
  • @Pointy: I got the code almost verbatim from a C# implementation. Could be why it looks like it's transcribed. ;) – Josh K Sep 29 '10 at 00:22