計數排序 -- GoLang實現

DY老王發表於2020-11-07

前提假設
  假設 n 個輸入元素中每一個都是在 0 到 k 區間內的一個整數,其中 k 為某個整數。

基本思想
  對每一個輸入元素 x,確定小於 x 的元素個數。然後利用這個值,可以直接把 x 放到它在輸出陣列中的位置。

例如
  對陣列 [ 2, 5, 3, 0, 2, 4, 0, 3 ] 進行計數排序,其中小於 4 的元素有 6 個,那麼 4 應該放在第 7 個輸出位置上。

虛擬碼實現:
說明:假設輸入是一個陣列 A[ 1 … n ], A.length = n。還需要另外兩個陣列
  B[ 1…n ]: 存放最終排序的輸出
  C[ 1…k ]: 提供臨時儲存空間,用於統計陣列 A 中每個元素的個數和統計陣列 A 中每個元素 x 的排名(即小於 x 的元素個數)

COUNTER-SORT(A, B, k)
let C[0..k] be a new array
for i = 0 to k
	C[i] = 0
for j = 1 to A.length
	C[A[j]] = C[A[j]] + 1
// C[i] now contains the number of elements equal to i.
for i = 1 to k
	C[i] = C[i] + C[i - 1]
// C[i] now contains the numer of elements less than or equal to i.
for j = A.length downto 1
	B[C[A[j]]] = A[j]
	C[A[j]] = C[A[j]] - 1

Golang原始碼實現:

// CounterSort 計數排序
func CounterSort(A, B []int, k int) {
	LengthA := len(A)
	C := make([]int, k+1)
	for i := 0; i < LengthA; i++ {
		C[A[i]]++
	}
	for j := 1; j < k+1; j++ {
		C[j] += C[j-1]
	}
	for l := LengthA - 1; l >= 0; l-- {
		B[C[A[l]]-1] = A[l]
		C[A[l]]--
	}
}

演算法分析:
時間複雜度:
  第5 ~ 7行的for迴圈和11 ~ 14的for迴圈耗時為 O(n),第8 ~ 10 行的for 迴圈耗時為 O(k)。所以演算法的時間複雜度為 O( n + k)。
穩定性:計數排序是穩定排序,其穩定性依賴於最後一次遍歷的for迴圈是 從後往前遍歷陣列 A 的,並且每次填充了一個元素後,C[ A[ l ] ] 執行自減操作。意味著當出現相同元素時,該相同的元素會被放到另一個相同元素的前面,即保持了穩定性。

問題延伸:
請設計一個演算法,它能夠對於任何給定的介於 0 到 k 之間的 n 個整數先進行預處理,然後在 O(1) 的時間內回答輸入 n 個整數中有多少個落在區間 [ a … b ] 內。你設計的演算法的預處理時間應為 O( n + k )。
評論區留下你的想法吧。

相關文章