W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
上一節(jié)我們介紹了計數(shù)排序,它適用于數(shù)據(jù)量
「基數(shù)排序 radix sort」的核心思想與計數(shù)排序一致,也通過統(tǒng)計個數(shù)來實現(xiàn)排序。在此基礎(chǔ)上,基數(shù)排序利用數(shù)字各位之間的遞進關(guān)系,依次對每一位進行排序,從而得到最終的排序結(jié)果。
以學(xué)號數(shù)據(jù)為例,假設(shè)數(shù)字的最低位是第
2.
繼續(xù)迭代,直到所有位都排序完成后結(jié)束。
圖 11-18 基數(shù)排序算法流程
下面來剖析代碼實現(xiàn)。對于一個
其中
此外,我們需要小幅改動計數(shù)排序代碼,使之可以根據(jù)數(shù)字的第
radix_sort.cpp
/* 獲取元素 num 的第 k 位,其中 exp = 10^(k-1) */
int digit(int num, int exp) {
// 傳入 exp 而非 k 可以避免在此重復(fù)執(zhí)行昂貴的次方計算
return (num / exp) % 10;
}
/* 計數(shù)排序(根據(jù) nums 第 k 位排序) */
void countingSortDigit(vector<int> &nums, int exp) {
// 十進制的位范圍為 0~9 ,因此需要長度為 10 的桶
vector<int> counter(10, 0);
int n = nums.size();
// 統(tǒng)計 0~9 各數(shù)字的出現(xiàn)次數(shù)
for (int i = 0; i < n; i++) {
int d = digit(nums[i], exp); // 獲取 nums[i] 第 k 位,記為 d
counter[d]++; // 統(tǒng)計數(shù)字 d 的出現(xiàn)次數(shù)
}
// 求前綴和,將“出現(xiàn)個數(shù)”轉(zhuǎn)換為“數(shù)組索引”
for (int i = 1; i < 10; i++) {
counter[i] += counter[i - 1];
}
// 倒序遍歷,根據(jù)桶內(nèi)統(tǒng)計結(jié)果,將各元素填入 res
vector<int> res(n, 0);
for (int i = n - 1; i >= 0; i--) {
int d = digit(nums[i], exp);
int j = counter[d] - 1; // 獲取 d 在數(shù)組中的索引 j
res[j] = nums[i]; // 將當前元素填入索引 j
counter[d]--; // 將 d 的數(shù)量減 1
}
// 使用結(jié)果覆蓋原數(shù)組 nums
for (int i = 0; i < n; i++)
nums[i] = res[i];
}
/* 基數(shù)排序 */
void radixSort(vector<int> &nums) {
// 獲取數(shù)組的最大元素,用于判斷最大位數(shù)
int m = *max_element(nums.begin(), nums.end());
// 按照從低位到高位的順序遍歷
for (int exp = 1; exp <= m; exp *= 10)
// 對數(shù)組元素的第 k 位執(zhí)行計數(shù)排序
// k = 1 -> exp = 1
// k = 2 -> exp = 10
// 即 exp = 10^(k-1)
countingSortDigit(nums, exp);
}
為什么從最低位開始排序?
在連續(xù)的排序輪次中,后一輪排序會覆蓋前一輪排序的結(jié)果。舉例來說,如果第一輪排序結(jié)果
相較于計數(shù)排序,基數(shù)排序適用于數(shù)值范圍較大的情況,但前提是數(shù)據(jù)必須可以表示為固定位數(shù)的格式,且位數(shù)不能過大。例如,浮點數(shù)不適合使用基數(shù)排序,因為其位數(shù)
res
和 counter
。Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: