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

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

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

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

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

0818b9ca8b590ca3270a3433284dd417.png

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

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

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

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

/**基数排序

* @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;

}

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