计数排序
计数排序是一种比时间复杂度O(nlogn)还要快速的一种排序,可以达到线性的时间复杂度。这种排序算法是通过数组的下标的位置来确定数据的正确位置的。
大致的过程如下:
代码实现:
public static int[] sort(int[] array){
//首先需要确定建立一个多大的数组,所以先要得到数组中的最大值
int max = array[0];
for (int i = 0; i < array.length; i++) {
if (array[i] > max){
max = array[i];
}
}
//通过最大值创建 max+1大小的数组,这里加1操作是要考虑 0 的情况
int[] count = new int[max + 1];
//遍历数列,填充计数数组
for (int i = 0; i < array.length; i++) {
count[array[i]]++;
}
//遍历计数数组,得到最后的结果数组
int index = 0;
int[] result = new int[array.length];
for (int i = 0; i < count.length; i++) {
for (int j = 0; j < count[i]; j++) {
result [index++] = i;
}
}
return result ;
}
此时可以得到这种排序算法的时间复杂度是O(n+m) 其中n是原始数列的数据长度,m是最后遍历的数组的长度,空间复杂度O(m)
但是:还有其他的问题无法得到,如果输入的数据是 1000,1001,1002,1003进行排序,那不是需要创建一个长度达到1005大小的数组?这就很得不偿失,其次,通过计数排序的操作,各个数据的也不能保证自己的顺序,无法知道哪个数据是第几个数据,或者原先这些数据对应着其他的数据,就比如五个老年人来排序,每个老年人有着自己的年纪,这是一一对应的,但是如果计数排序对于出现了重复的数据,直接加1操作,那就不知道谁对应的谁了。
于是对于计数排序还可以进行一个优化:
代码实现:
public static int[] sort2(int[] array){
//首先,计算需要创建的数组的长度,这时通过原始数列的最大值和最小值的查值来表示
int max = array[0];
int min = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max)
max = array[i];
if (array[i] < min)
min = array[i];
}
int dValue = max - min;
//通过差值创建 dValue+1大小的数组,这里加1操作是要考虑 0 的情况
int[] count = new int[dValue + 1];
for (int i = 0; i < array.length; i++) {
count[array[i]-min]++;
}
//对计数数组进行变化,使得后面的元素等于前面的元素之和,表示前面已经出现了多少个数了,记录顺序
for (int i = 1; i < count.length; i++) {
count[i] += count[i-1];
}
//倒序遍历原始数组,从计数数组找到正确的位置,输出到结果数组
int[] result = new int[array.length];
for (int i = array.length - 1; i >= 0; i--) {
result[count[array[i]-min]-1] = array[i];
count[array[i] - min]--;
}
return result;
}
但是还是有着局限性:
比如:传入的数据是1,10000001,10000002,10000003
那需要创建的就是10000004长度大小的数组了,实在是浪费空间,所以如果原始数列的最小值和最大值相差过大是不适合使用计数排序的,其次,如果出现了小数也是用不了计数排序的。