JavaScript中的基数排序

JavaScript中的基数排序,javascript,sorting,radix-sort,Javascript,Sorting,Radix Sort,我提出了以下几点,但可以预见,这是行不通的 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 < grou

我提出了以下几点,但可以预见,这是行不通的

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?
}
var t=新数组(a.length);
var r=4;
var b=64;
变量计数=新数组(1

for(变量i=0;i
这是一个问题,因为在第一次迭代中,
i
为零,因此
pref[0-1]
不会很好地工作


我手头没有基数排序的参考,无法确定您在这里实际应该做什么。

这个循环基本上做了相同的事情,以一种更加Javascript-y的方式:

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];
  }
}
for(变量div=1,基数=16;div<65536*65536;div*=基数){
var=[];
对于(变量i=0;i
与C程序员的做法不同,这个循环构建了一个列表列表,每个可能的4位值对应一个列表。我避免使用位移位运算符,因为这是Javascript,当它们工作时,当数字变大时,事情会变得有趣

从“a”中每个值的低位4位开始,代码将“a”的元素复制到其中一个“堆”的末尾,该“堆”对应于4位值。然后,它将这些堆聚集起来,并从低位4位为0、然后为1的所有值开始重建“a”(显然会有一些间隙,因此跳过这些间隙)在整个循环的每次迭代结束时,将除数乘以基数,以便检查下一组4位

一旦除数耗尽了可用的整数范围,就完成了


请注意,这只适用于正数数字。使用负数执行此操作会有点奇怪;将负数剥离到单独的数组中,翻转符号,排序,然后反转。对正数排序,然后最后粘合反转的负数(再次翻转符号)到已排序的正数的前面。

a
保存整数的输入数组?即使通过
新数组(长度)创建,为什么不在JS中对
count
pref
groups
?数组进行归零
从未定义的内容开始,
undefined+0
NaN
@Mike:首先,我甚至不太确定这种排序应该如何工作,因此我不确定什么是坏的。
count
已经被调零,
pref
在使用之前被初始化,
groups
不是数组。基数排序对b排序y查看排序键的片段,片段足够小,以至于一个片段的所有可能值都可以描述一个可管理数量的离散列表。想象一下,对您的CD收藏进行排序:首先按艺术家姓名的第二个字母排成一堆,然后按第一个字母排成一堆a-Z,然后再按第一个字母排成新的一堆。当您再次选择a-Z堆时将它们从左到右排列在一个架子上,它们被排序了!你能提供示例输入和输出吗?一个问题是“b”似乎表示每个整数的大小(以位为单位),这对于Javascript来说是错误的值。Javascript整数只有32位(或31位)。“pref”数组用于保存每个基数桶的值计数。如果我使用Javascript,我根本不会这样做;它就像一个转录的C程序。@Pointy:我几乎是从一个C#实现中一字不差地获得代码。这可能是它看起来像是转录的原因。;)这很有效,我会把它拆开,看看能不能把我的头绕在它身上。我想在我的一些代码中实现这种类型,您允许我这样做吗?当然;这是很平常的事。我喜欢你的问题,因为我一直在努力让我的一个孩子对我的旧唱片集进行基数排序的前景感到兴奋:-)
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];
  }
}