計數排序 的全網最詳細的講解

假設有這樣子一個題:數組裏有20個隨機數,取值範圍爲從0到10,要求用最快的速度把這20個整數從小到大進行排序。

你可能第一時間想到的是快速排序,因爲快排的時間複雜度是O(nlogn)。但是由於計數排序是基於桶排序然後由下表來確定元素的正確位置的。所以更快。

而經典的排序算法,無論是歸併排序,冒泡排序還是快速排序等等,都是基於元素之間的比較進行排序的。元素間比較是要耗費時間的。

在剛纔的題目裏,隨即整數的取值範圍是從0到10,那麼這些整數的值肯定是在0到10這11個數裏面。於是我們可以建立一個長度爲11的數組,數組下標從0到10,元素初始值全爲0,然後遍歷20個隨機數,每個整數按照其值對號入座,對應數組下標的原數進行加1操作。

然後當數組遍歷完後,數組中的每一個值代表數列中對應整數的出現的次數。

有了這個統計結果,排序就很簡單了,直接遍歷數組,輸出數組元素的下標值,元素的值是幾,就輸出幾次。

這就是桶排序!

那麼所謂的計數排序呢,就是在桶排序的基礎上加上了個前綴和

這段代碼在一開始補充了一個步驟,就是求得數列的最大整數值max,後面創建的數組countArray,長度就是max+1,以此保證數組最後一個下標是max。
從功能角度來看,這段代碼可以實現整數的排序。但是這段代碼其實並不嚴謹。
比如這個數列:95, 94, 91, 98, 99, 90, 99, 93, 91, 92。該數列最大值是99,但最小值是90,如果我們只以數列的最大值來決定統計數組的長度的話,就要創建長度爲100的數組,那麼就會浪費前面90個空間。
爲了解決這個問題,我們不再以(輸入數列的最大值+1)作爲統計數組的長度,而是以(數列最大值和最小值的差+1)作爲統計數組的長度。同時,數列的最小值作爲一個偏移量,用於統計數組的對號入座。
以剛纔的數列爲例,統計數組的長度爲 99-90+1=10,偏移量等於數列最小值90。
對於第一個整數95,對應的統計數組下標爲95-90=5,如圖所示:

在這裏插入圖片描述

這是一方面,另外,上述代碼知識簡單地按照統計數組的下標輸出了元素值,並沒有真正給數列排序。如果僅僅只是給整數排序,這樣並沒有問題。但如果是在現實業務裏,比如給學生的考試分數排序,如果遇到相同的分數就會分不清誰是誰。看看下面這個例子:
給出一個學生的成績表,要求按成績從底到高排序,如果成績相同,則遵循原表固有順序
在這裏插入圖片描述

當我們填充統計數組之後,我們只知道有兩個成績並列95分的學生,卻不知道誰是小紅,誰是小綠:
在這裏插入圖片描述
對此,我們只需在填充完統計數組之後,對統計數組做一下變形。我們仍然以學生的成績表爲例,把之前的統計數組進行變形,統計數組從第二個元素開始,每一個元素都加上前面所有元素之和:

在這裏插入圖片描述
相加的目的就是爲了讓統計數組存儲的元素值等於相應整數的最終排序位置。比如下標是9的元素值是5,代表原始數列的整數9最終的排序是在第5位。
接下來,我們創建輸出數組sortedArray,長度和輸入數列一致,然後從後向前遍歷輸入數列:
第一步,遍歷成績表最後一行的小綠:小綠是95分,找到countArray下標爲5的元素,值是4,代表小綠的成績排名是在第4位。
同時給countArray下標是5的元素值減1,從4變成3,代表着下次再遇到95分時,最終排名是第3位。在這裏插入圖片描述

第二步,遍歷成績表倒數第二行的小白:小白是94分,找到countArray下標是4的元素,值是2,代表小白的成績排名在第2位。
同時,給countArray下標是4的元素值減1,從2變成1,代表下次再遇到94分的成績時(實際上已經遇不到了),最終排名是第1位。
在這裏插入圖片描述

第三步,遍歷成績表倒數第三行的小紅:小紅是95分,找到countArray下標是5的元素,值是3(最初是4,減1變成了3),代表小白的成績排名在第3位。
同時,給countArray下標是5的元素值減1,從3變成2,代表下次再遇到95分的成績時(實際上已經遇不到了),最終排名是第2位。

在這裏插入圖片描述

因此,同樣是95分的小紅和小綠就能清楚地排出順序,所以優化版的計數排序屬於穩定排序。
後面的遍歷過程依此類推。
改進版本的計數排序代碼如下:
如果原始數列的規模是N,最大最小整數的差值是M,由於代碼中第1、2、4步都涉及到遍歷原始數列,運算量都是N,第3步遍歷統計數列,運算量是M,所以總體運算量是3N+M,去掉係數,時間複雜度是O(N+M)。
至於空間複雜度,如果不考慮結果數組,只考慮統計數組的話,空間複雜度是O(M)。
雖然計數排序看上去很強大,但是它存在兩大侷限性:
1.當數列最大最小值差距過大時,並不適用於計數排序
比如給定20個隨機整數,範圍在0到1億之間,此時如果使用計數排序的話,就需要創建長度爲1億的數組,不但嚴重浪費了空間,而且時間複雜度也隨之升高。
2.當數列元素不是整數時,並不適用於計數排序
如果數列中的元素都是小數,比如3.1415,或是0.00000001這樣子,則無法創建對應的統計數組,這樣顯然無法進行計數排序。
正是由於這兩大侷限性,才使得計數排序不像快速排序、歸併排序那樣被人們廣泛適用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章