概念
以數組元素值爲鍵,出現次數爲值存進一個臨時數組,最後再遍歷這個臨時數組還原回原數組。因爲 JavaScript的數組下標是以字符串形式存儲的,所以計數排序可以用來排列負數,但不可以排列小數。
複雜度
最好:O(n + k),k是最大值和最小值的差。
最壞:O(n + k)
平均:O(n + k)
分類
常規計數排序
代碼
function counting_sort(nums) {
let arr = []
let leg = nums.length;
let max = Math.max(...nums)
let min = Math.min(...nums)
for (let i = 0; i < leg; i++) {
let temp = nums[i]
arr[temp] = arr[temp] + 1 || 1
}
let index = 0
for (let i = min; i < max; i++) {
while (arr[i] > 0) {
nums[index++] = i
arr[i]--
}
}
}
var sortArr = [9, 6, 3, 5, 2, 1, 7, 343, 6, 643, 243, 544, 5, 63, 234, 0, 56, 123]
counting_sort(sortArr)
console.log(sortArr)
// [0, 1, 2, 3, 5, 5, 6, 6, 7, 9, 56, 63, 123, 234, 243, 343, 544, 123]
缺點
優化計數排序
把每一個數組元素都加上 min 的相反數,來避免特殊情況下的空間浪費,通過這種優化可以把所開的空間大小從 max+1 降低爲 max-min+1,max 和 min 分別爲數組中的最大值和最小值。
比如數組 [103, 102, 101, 100],普通的計數排序需要開一個長度爲 104 的數組,而且前面 100 個值都是 undefined,使用該優化方法後可以只開一個長度爲 4 的數組。
function counting_sort(nums) {
let arr = []
let leg = nums.length;
let max = Math.max(...nums)
let min = Math.min(...nums)
let mark = 0
let add = -min
// 加上最小值的相反數來縮小數組範圍
for (let i = 0, len = nums.length; i < len; i++) {
mark += 1
let temp = nums[i];
temp += add;
arr[temp] = arr[temp] + 1 || 1;
}
console.log(arr)
let index = 0
for (let i = min; i <= max; i++) {
let temp = arr[i + add];
mark += 1
while (temp > 0) {
mark += 1
nums[index++] = i;
temp--;
}
}
console.log(mark)
}
var sortArr = [9, 6, 3, 5, 2, 1, 7, 343, 6, 643, 243, 544, 5, 63, 234, 0, 56, 123, 9999]
counting_sort(sortArr)
console.log(sortArr)
// 10038
// [0, 1, 2, 3, 5, 5, 6, 6, 7, 9, 56, 63, 123, 234, 243, 343, 544, 643, 9999]
使用感受
就計數排序而言,最好數的最大最小差異不是很大,如果比較值本身差異很大,創建的數據空間就會越大,遍歷數也會變多, 而且這個優化的計數排序如果數是正負都有的 那個 空間大小從 max+1 降低爲 max-min+1 這個就會變成相加的,反而會讓性能變差,而且這種優化感覺沒什麼大的用處