Question

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?
}
Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top