摘要
基數排序是進行整數序列的排序,它是將整數從個位開始,直到最大數的最後一位截止,每一個進位(比如個位、十位、百位)的數進行排序比較。
每個進位做的排序比較是用計數排序的方式處理,所以基數排序離不開計數排序。
邏輯
對整數依次從個位數、十位數...進行排序。基數排序非常適合用於整數排序
對每一輪的排序可以使用計數排序的方法處理
基數排序和計數排序來做個簡單的比較時,可以看到基數排序每一個進位都要進行一次計數排序,所以比較迴圈多一些。但是每個進位制上的數範圍是 0 到 9 這 10 個數,所以需要開闢的空間相對可控和少一些。下面來詳細瞭解一下。
流程
- 獲取序列中的最大值,確定排序的最大位數
- 從個位起,使用計數排序的方式處理序列
實現
找出最大值, max 的初始值為序列的 first 元素。迴圈從 1 開始。
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
對序列從個位開始排序(計數排序的方式)。這裡要留意,divider 的每一次增加是 divider *= 10
,相當於向前進一位。
這裡的每一輪比較排序中,交換的是序列中的元素,而不是某個進位上的數字,這個要特別注意。
for (int divider = 1; divider <= max; divider *= 10) {
CountingSort(divider);
}
下面的排序就是用計數排序來處理,對計數排序不太明白的可以看上一期介紹計數排序。
這裡有兩點需要留意:
- 這裡直接開闢了 10 個儲存空間,是因為,每一個進位上的數只有 0 到 9 這 10 個數
- 這裡通過
divider % 10
這個方式獲取到該進位上的數字。
private void CountingSort(int divider) {
// 開闢記憶體空間,儲存次數
int[] counts = new int[10];
// 統計每個整數出現的次數
for (int i = 0; i < array.length; i++) {
counts[array[i] / divider % 10]++;
}
// 累加次數
for (int i = 1; i < counts.length; i++) {
counts[i] += counts[i-1];
}
// 從後往前遍歷陣列,放在有序陣列中的位置
int[] newArray = new int[array.length];
for (int i = array.length - 1; i >= 0; i--) {
newArray[--counts[array[i] / divider % 10]] = array[i];
}
// 將有序陣列覆蓋到 array
for (int i = 0; i < newArray.length; i++) {
array[i] = newArray[i];
}
}
時間和空間複雜度
- 最好、最壞、平均時間複雜度:O(d*(n+k))
- 空間複雜度:O(n+k)
- 屬於穩定排序
d 是最大值的位數,k 是進位制