1、算法思想
計數排序是一種適合於最大值和最小值的差值不是不是很大的排序。
基本思想:就是把數組元素作爲數組的下標,然後用一個臨時數組統計該元素出現的次數,例如 temp[i] = m, 表示元素 i 一共出現了 m 次。最後再把臨時數組統計的數據從小到大彙總起來,此時彙總起來是數據是有序的。
爲方便理解我還準備了動圖:
2、代碼實現
void countSort(int[] arr) {
if(arr == null || arr.length < 2) return arr;
int n = arr.length;
int max = arr[0];
// 尋找數組的最大值
for (int i = 1; i < n; i++) {
if(max < arr[i])
max = arr[i];
}
//創建大小爲max的臨時數組
int[] temp = new int[max + 1];
//統計元素i出現的次數
for (int i = 0; i < n; i++) {
temp[arr[i]]++;
}
int k = 0;
//把臨時數組統計好的數據重寫原數組
for (int i = 0; i <= max; i++) {
for (int j = temp[i]; j > 0; j--) {
arr[k++] = i;
}
}
}
上面的代碼中,我們是根據 max 的大小來創建對應大小的數組,假如原數組只有10個元素,並且最小值爲 min = 10000,最大值爲 max = 10005,那我們創建 10005 + 1 大小的數組不是很喫虧,最大值與最小值的差值爲 5,所以我們創建大小爲6的臨時數組就可以了。
也就是說,我們創建的臨時數組大小 (max - min + 1)就可以了,然後在把 min作爲偏移量。優化之後的代碼如下所示:
void countSort(int* arr) {
if(arr == null || arr.length < 2) return arr;
int n = arr.length;
int min = arr[0];
int max = arr[0];
// 尋找數組的最大值與最小值
for (int i = 1; i < n; i++) {
if(max < arr[i])
max = arr[i];
if(min > arr[i])
min = arr[i];
}
int d = max - min + 1;
//創建大小爲max的臨時數組
int[] temp = new int[d];
//統計元素i出現的次數
for (int i = 0; i < n; i++) {
temp[arr[i] - min]++;
}
int k = 0;
//把臨時數組統計好的數據彙總到原數組
for (int i = 0; i < d; i++) {
for (int j = temp[i]; j > 0; j--) {
arr[k++] = i + min;
}
}
}
3、算法分析
- 時間複雜度:O(n+k)
- 空間複雜度:O(k)
- 穩定性:穩定排序
- 非原地排序
注:K表示臨時數組的大小。