关于在Java中实现Radix排序的问题

时间:2014-09-01 01:28:30

标签: java algorithm sorting bit-manipulation radix-sort

以下基数排序从Sedgewick's Algorithms textbook获取四次计数排序(256个桶,32位整数,从最低有效位开始)。

public class LSD {
    private final static int BITS_PER_BYTE = 8;

    // LSD sort an array of integers, treating each int as 4 bytes
    // assumes integers are nonnegative
    // [ 2-3x faster than Arrays.sort() ]
    public static void sort(int[] a) {
    int BITS = 32;                 // each int is 32 bits 
    int W = BITS / BITS_PER_BYTE;  // each int is 4 bytes
    int R = 1 << BITS_PER_BYTE;    // each bytes is between 0 and 255
    int MASK = R - 1;              // 0xFF

    int N = a.length;
    int[] aux = new int[N];

    for (int d = 0; d < W; d++) {         

        // compute frequency counts
        int[] count = new int[R+1];
        for (int i = 0; i < N; i++) {           
            int c = (a[i] >> BITS_PER_BYTE*d) & MASK;
            count[c + 1]++;
        }

        // compute cumulates
        for (int r = 0; r < R; r++)
            count[r+1] += count[r];

        // for most significant byte, 0x80-0xFF comes before 0x00-0x7F
        if (d == W-1) {
            int shift1 = count[R] - count[R/2];
            int shift2 = count[R/2];
            for (int r = 0; r < R/2; r++)
                count[r] += shift1;
            for (int r = R/2; r < R; r++)
                count[r] -= shift2;
        }

        // move data
        for (int i = 0; i < N; i++) {
            int c = (a[i] >> BITS_PER_BYTE*d) & MASK;
            aux[count[c]++] = a[i];
        }

        // copy back
        for (int i = 0; i < N; i++)
            a[i] = aux[i];
    }
}

我理解除了这部分之外的大部分代码:

if (d == W-1) {
    int shift1 = count[R] - count[R/2];
    int shift2 = count[R/2];
    for (int r = 0; r < R/2; r++)
        count[r] += shift1;
    for (int r = R/2; r < R; r++)
        count[r] -= shift2;
}

这段代码的目的是什么?谢谢!

1 个答案:

答案 0 :(得分:4)

代码块完全符合评论所说的内容:

  

对于最高有效字节,0x80-0xFF出现在0x00-0x7F

之前

原因是:由于您使用的是int,因此最重要的位是符号位。因此,0x80-0xFF范围内具有最高有效字节的数字是负数,因此应放在正数之前,其中最重要的字节在0x00-0x7F范围内。

如果你问的是代码块是如何实现的,这里有一个简短的想法:

由于您了解了数据的移动方式,因此我假设您了解count[]在整个代码中的作用。在代码块中,R是上限,0xFF + 1R / 20x7F + 1。因此,count[R] - count[R / 2]0x800xFF范围内的总数。因此,通过添加count[R] - count[R / 2]count[0 .. R / 2]的转换并从count[R / 2 .. R]中减去它将有助于0x000x7F范围内的数字具有更高的count值比0x800xFF范围内的数字要多,导致 0x80-0xFF最终出现在0x00-0x7F 之前。

最后,您可能很好奇:如果第一位是符号位,为什么11111111大于10000001?那不是-(127) < -(1)吗?这是因为在计算机系统中,我们使用2's compliment代替签名整数,因此11111111实际上意味着-1,而10000001实际上意味着-127