排序的思路常规的就是基于比较,比如常见的快排,冒泡等,这种排序最快也是Onlogn。

非比较的排序思路基本是用一个辅助数组,把待排数组的元素大小作为索引放入辅助数组,用辅助数组的位置来记录大小,空间换时间。

适用场景:待排元素的值有一个范围,并且范围是可以接受的。

方法:这里会涉及几个参数,作为接受参数,必须有待排数组A,以及数组值得范围k。在函数实现的内部,要用k新建一个计数数组B,以及一个结果数组C。

先说最简单的情形,假设所有待排元素是互异的,那么只需要遍历一次A,把A的每一个元素的值作为B索引,存入B数组中。最后再遍历一次B,把存入的元素放入结果C中。可以看到,辅助数组B的位置体现了待排数组A的大小关系。


更加常见的,比如说基于数组中出现的次数做排序。出现次数一般而言会稳定在一个范围内,所以适用于非比较排序思路。

B数组就不能简单的只存储特定值的元素了,而应该存储特定值元素的个数。然后再遍历一次B,做一次向前的累加,就得到了特定值的元素的位置,即值为特定值的元素的个数加上比这个值小的元素的个数。此时,B数组的值即为相应元素的个数,比如b[i]=j,那么i和小于i的元素出现的次数为j,元素i的位置就是j。每得到一个i就放在j位置,同时将b[i]减1,其他的元素i位置就应该往前放。为了使得排序是稳定的,这里有一个小技巧,最后以A为索引遍历B时,A应该从后向前,这样,A中最后的i就让然放在最后的位置,倒数第二个i位于其前,以此类推。

相关代码:

public static int[] countingSort(int[] array, int k){
int[] counting = new int[k + 1];
int[] result = new int[array.length];
for(int i : array){
counting[i]++;
}
for(int i = 1; i < counting.length; i++){
counting[i] = counting[i - 1] + counting[i];
}
for(int i = array.length - 1; i >= 0; i--){
result[counting[array[i]] - 1] = array[i];
counting[array[i]] --;
}
return result;
}

该算法的时间为On+k。线性。