基本思想: 对每一个输入元素x,确定出小于x的元素个数。有了这一信息,就可以把x直接放到它在最终输出数组中的位置上。例如,如果有17个元素小于x,则x就属于第18个输出位置。
计数排序是一个非基于比较的排序算法。它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。当然这是一种牺牲空间换取时间的做法,而且当O(k)>O*(n*log(n))的时候其效率反而不如基于比较的排序(基于比较的排序的时间复杂度在理论上的下限是*O(n*log(n)), 如归并排序,堆排序),计数排序是稳定的。
算法过程: 假设输入的线性表L的长度为n,L=L1,L2,..,Ln;线性表的元素属于有限偏序集S,|S|=k且k=O(n),S={S1,S2,..Sk};则计数排序可以描述如下:
1、扫描整个集合S,对每一个Si∈S,找到在线性表L中小于等于Si的元素的个数T(Si);
2、扫描整个线性表L,对L中的每一个元素Li,将Li放在输出线性表的第T(Li)个位置上,并将T(Li)减1。
给定数组a[8]={2,5,3,0,2,3,0,3};
Java代码:
public class LinearTimeSorter {
/**
* 计数排序,所有的元素都在0和max之间。
*/
public static void countingSort(int[] array, int fromIndex, int toIndex, int max) {
int[] counting = new int[max + 1];
for (int i = fromIndex; i < toIndex; i++) {
counting[array[i]]++;
} // counting[i]现在包含值为i的个数
for (int i = 1; i < counting.length; i++) {
counting[i] += counting[i-1];
} // counting[i]现在包含值小于等于i的个数
int[] tempArray = new int[toIndex - fromIndex];
for (int i = toIndex - 1; i >= 0; i--) { // 注意:这里是反向遍历,只有这样才是稳定的
tempArray[--counting[array[i]]] = array[i];
}
// copy back
System.arraycopy(tempArray, 0, array, fromIndex, tempArray.length);
}
public static void countingSort(int[] array, int max) {
countingSort(array, 0, array.length, max);
}
/**
* 计数排序,所有的元素都在min和max之间。
*/
public static void countingSortMinMax(int[] array, int fromIndex, int toIndex, int min, int max) {
int[] counting = new int[max - min + 1];
for (int i = fromIndex; i < toIndex; i++) {
counting[array[i]-min]++;
} // counting[i]现在包含值为(i+min)的个数
for (int i = 1; i < counting.length; i++) {
counting[i] += counting[i-1];
} // counting[i]现在包含值小于等于(i+min)的个数
int[] tempArray = new int[toIndex - fromIndex];
for (int i = toIndex - 1; i >= 0; i--) {
tempArray[--counting[array[i] - min]] = array[i];
}
// copy back
System.arraycopy(tempArray, 0, array, fromIndex, tempArray.length);
}
public static void countingSortMinMax(int[] array, int min, int max) {
countingSortMinMax(array, 0, array.length, min, max);
}
/**
* 计数排序,自动决定min和max。
*/
public static void countingSort(int[] array) {
if (array.length <= 1) return;
int min = array[0];
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (min > array[i]) min = array[i];
if (max < array[i]) max = array[i];
}
countingSortMinMax(array, min, max);
}
public static void main(String[] args) {
int[] a = new int[] {2, 5, 3, 0, 2, 3, 0, 3};
countingSort(a, 5);
System.out.println(Arrays.toString(a));
a = new int[] {0, 3, 1, -2, 0, 1, -2, 1};
countingSortMinMax(a, -2, 3);
System.out.println(Arrays.toString(a));
}
}