分配排序之基數排序
基數排序是在計數排序上的應用擴展,是分配排序的一個特例,我們已經知道計數排序(桶排序)適用於小數範圍內的排序,對於大數則效率不高,而今天要說的基數排序,利用了進制基數的特點,將大數拆解爲進制內範圍的小數,多次執行計數或其他穩定排序,實現了大數範圍內的排序功能。
例如對於兩位數之間的排序問題,我們一般從十位開始比較,十位相同的數,再比較個位,最終得出想要的結果,基數排序的過程大致如此,不同之處在於對於十位或個位相同的數,我們採用計數排序的處理,中間不需要進行元素之間的比較。
基數排序分爲高位優先法(most significant digit first, MSD)與低位優先法(least significant digit first, LSD),計算機在實現高位優先法時,需要進行嵌套分配桶空間,是一個遞歸分治的算法,執行起來比較複雜,因此LSD的實現則更爲常見。
LSD基於數組的實現代碼如下:
import java.util.Arrays;
public class RadixSort {
public static void main(String[] args) {
int[] arr = new int[] { 97, 53, 88, 59, 26, 41, 88, 31, 22 };
arr = radixSort(arr, 9, 2, 10);
System.out.println(Arrays.toString(arr));
}
/**
*
* @param array 排序序列
* @param n 排序序列元素數
* @param d 排序位數(兩位數傳入2)
* @param r 基
*/
public static int[] radixSort(int[] array, int n, int d, int r) {
// 內部桶排序時用以保存各桶中的元素數
int[] count = new int[r];
// 按照不同基位進行桶排序時存放元素
int[] tmpArray = new int[n];
// 模除數,計算桶位
int radix = 1;
// 臨時變量,用於計算每個元素的桶位,避免重複聲明
int k = 0;
// 進行d輪計數排序(/桶排序)
for (int i = 0; i < d; i++) {
// 每輪循環,須重新初始化count數組
for (int j = 0; j < r; j++) {
count[j] = 0;
}
// 遍歷原始數組,計算每個桶位的元素數,存儲於count數組
for (int j = 0; j < n; j++) {
k = (array[j] / radix) % r;
count[k]++;
}
// 計數器對應位數值修改爲下一位的開始位置
for (int j = 1; j < r; j++) {
count[j] = count[j] + count[j - 1];
}
// 進行桶排序過程
for (int j = n - 1; j >= 0; j--) {
// 計算元素桶位
k = (array[j] / radix) % r;
count[k]--;
tmpArray[count[k]] = array[j];
}
// 回寫到原數組
for (int j = 0; j < n; j++) {
array[j] = tmpArray[j];
}
// 基位遞增
radix *= r;
}
return array;
}
}
小結
基數排序的主要思想是按照基數對排序元素進行拆分,拆分後的每個值都屬於進制內的數值,在此基礎上,按照每一位進行桶排序,與直觀的理解不同,由於計算機在處理遞歸分治算法時較爲複雜,因此一般實現方式是LSD–低位優先的算法,稍微考慮下,高位優先MSD與低位LSD之間的直觀區別僅僅是排序時處理的方向不一樣。
推薦資料:
Radix sort - Wikiwand
歡迎關注我的公衆號,瞭解更多內容: