資料結構與演算法 | 計數排序
在之前的部落格中,我介紹過一種非比較排序——計數排序。
計數排序的原理很簡單,就是用乙個陣列來統計每種數字出現的次數,然後按照大小順序將其依次放回原陣列,達成排序的目的。
但是計數排序有乙個很嚴重的問題,就是其只能對整數進行排序,一旦遇到字串時,就無能為力了。
為了彌補上述的缺點,針對於字串的基數排序誕生了。
基數排序在計數排序的基礎上進行了改進,將排序工作拆分為多個階段,每乙個階段只根據乙個字元進行排序,一共排序k輪(k為資料長度)
例如我們需要對一組三個英文本母組成的字串進行排序,按照以上規則,進行三輪排序。
(ps:這裡用的lsd法)我們從低位往高位開始排,按照計數排序的思想,統計所有出現過的字元,按照其在ascii表中的順序依次排序,得到以下結果
此時在第一輪的基礎上,對倒數第二個字元進行排序
在第二輪的基礎上,再對第乙個字元進行排序
如此一來,就得到了有序的序列。這種將字串拆分為多位,每位進行計數排序的演算法,就是基數排序。
從上面來看,每一位的排序都基於上一位的基礎,所以這也就要求我們的計數排序必須是穩定的,否則前後順序無法保證,多輪的排序就沒有了意義,下面就介紹如何實現穩定的計數排序。
在之前的部落格中,我當時介紹的計數排序是不穩定的,下面就對其進行改造,將其變為穩定排序。
那要這麼做呢?我們知道,計數排序中的統計陣列中儲存了每個數字出現的次數,而我們還原時也只是按照數字來依次將其放回,這也就是其不穩定的原因,因為統計陣列絲毫沒有關心其在原陣列中的位置。
要改進這一點,可以通過以下方法來實現,只需要加上幾行簡單的**即可。
//保證計數排序穩定,對陣列變形,統計陣列的每乙個位置的值為前面所有數字的數量合
//變形後每個位置的值即為該資料的排序的序號
int sum =0;
for(
int i =
0; i < range; i++
)
如上面**,我們需要讓統計陣列中不再記錄陣列出現的次數,而是記錄該位置前面所有數字出現的次數和,這種方式能讓我們巧妙地得到序號。
例如下圖
這樣做的目的是什麼呢?
//按照原陣列的資料的位置,倒序將資料放回原位,確保穩定性
vector<
int>
temp
(arr.
size()
,0);
for(
int i = arr.
size()
-1; i >=
0; i--
)
因為我們此時統計陣列中每乙個位置的值,變成了由陣列開頭到那個位置所有元素的和,這也就意味著,他此時變成了乙個排名。
例如在原資料中有兩個93,乙個在前,乙個在後,並且統計陣列中93的位置為7。
我們通過上述方法,從後往前遍歷時,將後面的93放到第七個位置,接著統計陣列對應位置的排名減一,此時當我們放入前面的93時,他就變成了第六位,這樣就保證了其穩定性。
這個看**更好理解,思路都寫在了注釋中,改造完後的計數排序**如下。
void
countsort
(vector<
int>
& arr)
if(arr[i]
< min)
}int range = max - min +1;
vector<
int>
count
(range,0)
;//統計陣列
//統計每種數字出現的次數
for(
int i =
0; i < arr.
size()
; i++
)//保證計數排序穩定,對陣列變形,統計陣列的每乙個位置的值為前面所有數字的數量合
//變形後每個位置的值即為該資料的排序的序號
int sum =0;
for(
int i =
0; i < range; i++
)//按照原陣列的資料的位置,倒序將資料放回原位,確保穩定性
vector<
int>
temp
(arr.
size()
,0);
for(
int i = arr.
size()
-1; i >=
0; i--
) arr = temp;
//將臨時資料拷貝回原陣列
}
在寫基數排序之前,還有乙個小問題需要說明一下,由於前面我們所說的情況都是字串長度相等的時候,如果字串長度不相同時,怎麼處理呢?
因為字串並不像整數一樣排序依賴於長度,其排序主要依賴於字典序,所以我們以字串中最長的資料為標準,而長度不足的在尾部補零即可。
實現**如下
int
getindex
(const string& str,
int index)
return str[index];}
void
radixsort
(vector
& arr,
int maxlen)
//保證計數排序穩定,對陣列變形,統計陣列的每乙個位置的值為前面所有數字的數量合
//變形後每個位置的值即為該資料的排序的序號
int sum =0;
for(
int j =
0; j < count.
size()
; j++
)//按照原陣列的資料的位置,倒序將資料放回原位,確保穩定性
for(
int j = arr.
size()
-1; j >=
0; j--
) arr = temp;
}}
什麼是基數排序?
基數排序 radix sort 是桶排序的擴充套件,它的基本思想是 將整數按位數切割成不同的數字,然後按每個位數分別比較。具體做法是 將所有待比較數值統一為同樣的數字長度,數字較短的數前面補零。然後,從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以後,數列就變成乙個有序序列。通...
動畫 什麼是基數排序?
基數排序和計數排序一樣無需進行比較和交換,和桶排序一樣利用分布和收集兩種基本操作進行排序。基數排序是把每乙個元素拆成多個關鍵字,乙個關鍵字可以在每乙個元素上同等的位置進行計數排序,乙個元素拆成多個關鍵字可以看作是要進行幾輪分桶,以乙個元素最長的長度為準。基數排序可以看成多 單 關鍵字的排序,可以想象...
排序 基數排序
基數排序 radix sort 是屬於 分配式排序 distribution sort 基數排序法又稱 桶子法 bucket sort 或bin sort,顧名思義,它是透過鍵值的部份資訊,將要排序的元素分配至某些 桶 中,藉以達到排序的作用。排序思想 首先按照資料的最低位 個位 將資料分配到0 9...