排序算法之——基数排序(Java实现)

        今天,我来讲一讲基数排序。基数排序是一种用在老式穿卡机上的算法。一张卡片有80列,每一列可以在12个位置中的任一处穿孔。排序器可以被机械地“程序化”,以便对一叠卡片中的每一列进行检查,再根据穿孔的位置将它们放入12个盒子里。这样,操作员就可以逐个地将它们收集起来,其中第一个位置穿孔的放在最上面,第二个其次,等等。对于十进制数字来说,每列中只用到10个位置(另两个位置用于编码非数值字符)。一个d位数占用d个列。因为卡片排序器一次只能查看一个列,因此,要对n张卡片上的d位数进行排序,就需要用到排序算法。

        从直觉上来看,人们可能会觉得应该按最高有效位进行排序,然后再对每个盒子中的数递归地排序,最后再把结果合并起来。不幸的是,为排序每一个盒子中的数,10个盒子中的9个必须先放在一遍,这个过程产生了许多需要加以记录的中间卡片堆。

        与人们的直觉相反,基数排序是首先按最低有效位数字进行排序,以解决卡片排序问题。同样,把各堆卡片收集成一叠,其中0号盒子中的在1号盒子中的前面,后者又在2号盒子中的前面,等等。然后,对整个一叠卡片按次低有效位排序,并把结果同样地合并起来。重复这个过程,直到对所有的d位数字都进行了排序。所以,仅需要d遍就可以将一叠卡片排好序。

下图说明了基数排序作用于“一叠”共7个3位数的过程。


这里也有很重要的一点,就是基数排序的稳定性,所谓稳定性,是指当有多个相同元素的值时,排序后,他们的相对次序不变。参考计数排序

想想很好理解,因为操作员把卡片从盒子里拿出来时不能改变它们的次序,否则不是乱套了吗,即使数字相同,所属者也可能是不同的。

基数排序要保持稳定,那在对每一位进行排序的时候就必须使用一个稳定的算法,这里我们就可以使用计数排序作为这个子算法。参考计数排序

基数排序的代码是很直观的。

    /**基数排序
     * @param A 需要排序的数组,返回时已经排序
     * @param d 最高位,最低位是1
     */
    public int[] RadixSort(int[] A, int d){
        int[] B = A.clone();
        for(int i = 1; i <= d; i++){
            //调用某一稳定排序对A数组进行排序(基于i位)
            CountingSort2(A, B, i);
            A = B.clone();
        }
        return A;
    }
这里的CountingSort和我之前的博客写的略有区别,对判断的依据做了修改,因为是按位判断

    /**
     * 计数排序变种,根据某一位进行排序,k不需要,因为每一位数字在0到9之间。
     * @param A
     * @param B
     * @param index
     */
    public void CountingSort2(int[] A, int[] B, int index){
        int[] C = new int[10];
        for(int i = 0; i < A.length; i++){
            C[getDigit(A[i], index)]++;
        }
        for(int i = 1; i < 10; i++){
            C[i] += C[i - 1];
        }
        for(int i = A.length - 1; i >= 0; i--){
            B[C[getDigit(A[i], index)] - 1] = A[i];
            C[getDigit(A[i], index)]--;
        }
    }
这里用到了一个函数,是获得某一位,代码很简单:
    /**
     * 获得数字的某位
     * @param digit 数字
     * @param i 1-d位
     * @return 单位数字
     */
    public int getDigit(int digit, int i){
        int result = 0;
        for(int j = 0; j < i; j++){
            result = digit % 10;
            digit /= 10;
        }
        return result;
    }

如果对代码有疑惑可以看我的github源码,上面有所有方法的单元测试:https://github.com/qjkobe/IntroductionToAlgorithms


如果发现问题,请立刻告诉我。我可不想误人子弟