常見的排序算法,例如:冒泡,選擇,快速等等。他們都是基於比較實現的排序算法。最快的快速排序算法的時間複雜度爲。而計數排序是一種特殊的排序算法,它的時間複雜度爲,在數據較多,數據範圍較小的情況下,計數排序比快速排序的效率更高。與此同時,計數排序是穩定的,相同的數據相對順序保持不變。
示例:待排序數組array爲[98, 97, 96, 98, 95, 100, 96, 98, 100, 99]。
算法步驟:
1、找到最小值min,最大值max,得到數據的極差1range = max - min + 1。
2、創建計數數組count,大小爲range。
3、順序遍歷原數組,索引爲i,數據element = array[i],映射到count數組中索引爲index = element - min,將count[index]加1。表示數組中的元素element的個數加1。
4、順序遍歷count數組,索引爲i,計算count[i] = count[i - 1] + count[i]。
5、逆序遍歷原數組array,索引爲i,數據element = array[i],映射到count數組中索引爲index = element - min,將count[index]減1後的數據爲j,然後將element保存到結果數組(res)中的索引爲j的位置。
演示視頻如下:
計數排序
由此可以看出:算法共有四次循環,其中三次遍歷原數組,時間複雜度爲,若數據範圍爲k,則遍歷count數組的時間複雜度爲,故總的時間複雜度爲。不計算輸出數組的情況下,空間複雜度爲。
可以發現,數據範圍對計數排序的複雜度影響較大。因此當數據範圍非常大的時候不宜使用此算法。
Java代碼實現如下:
/**
* 計數排序
* <p>創建日期:2020-06-05 11:56</p>
*
* @author PengHao
*/
public class CountSort {
/**
* <p>計數排序</p>
* <p>時間複雜度爲O(3n+k)</p>
* <p>空間複雜度爲O(k)</p>
*
* @param src 待排序數組
* @return 排好序的數組
*/
public static int[] countSort(int[] src) {
// 數組中的最小值
int min = src[0];
// 數組中的最大值
int max = src[0];
for (int value : src) {
if (value < min) {
min = value;
} else if (value > max) {
max = value;
}
}
// 數組中的數據範圍
int range = max - min + 1;
// count[i]表示數組src中數據min + i的個數
int[] count = new int[range];
for (int value : src) {
count[value - min]++;
}
// 累計,使得count[i]保存src中小於等於min + i的數據的個數
for (int i = 1; i < range; i++) {
count[i] += count[i - 1];
}
// 結果數組
int[] res = new int[src.length];
// 倒序遍歷原數組,保持排序的穩定性
for (int i = src.length - 1; i >= 0; i--) {
// 獲取數據在count數組中的索引
int index = src[i] - min;
// 個數減1
count[index]--;
// 數據src[i]排序後的索引是count[index]
res[count[index]] = src[i];
}
return res;
}
}
代碼沒有進行安全檢查,所以待排序數組不能爲空,並且至少有1個元素。
數學中極差的定義爲:range = max - min。 ↩︎