1. 程式人生 > 其它 >桶排序——計數排序和基數排序

桶排序——計數排序和基數排序

桶排序的基本思想:

* 之前所涉及到的簡單排序及複雜排序中的歸併排序,快速排序和堆排序都屬於基於比較的排序
* 而桶排序則是一個不基於比較的排序
*
* 桶排序這類不基於比較的排序的適用範圍較為有限
* 其核心思想是把有著相同特點的某些元素裝入一個桶,桶與桶之間是有序的,桶的內部也是有序的
* 最終只要按照這種順序把桶中元素依次倒出即可達到有序
*
* 桶排序適用於已知要排的陣列的大致範圍,且這個範圍不大的情況下,可以使用桶排序來進行

 

1.計數排序:

* 計數排序思想即用到了map陣列的思想,去統計範圍內每一個值出現的次數,再從小到大去遍歷這些可能的值*將其依次輸出 

程式碼實現:

 1 //桶排序之一——計數排序的實現
 2     public static void CountSort(int[] arr,int min,int max) {//min--max為arr的可能取值範圍
 3         int len = max - min + 1;
 4         int[] count = new int[len];
 5         for (int i = 0; i < arr.length; i++) {
 6             count[arr[i] - min]++;
 7         }
 8         int
cnt = 0; 9 while (cnt < arr.length) { 10 for (int i = 0; i < len; i++) { 11 while (count[i] > 0) { 12 arr[cnt++] = i + min; 13 count[i]--; 14 } 15 } 16 } 17 }

 

2.

* 基數排序:(一般針對整形數進行使用(因為其位數已知))
* 其核心思想就是從低位到高位對每一位進行按位排序(因為每一位就10種情況,即範圍有限,所以可以使用桶排序思想)
* 只要保證每次低位排完以後,對在同一個桶的元素做到先進先出,那麼就可以處理掉每位的排序問題
* 又因為越高位在比較數的大小時優先順序越高,越有決定性,所以放到越後面來排

 

程式碼實現及解析:

 1 //程式碼實現:(其程式碼實現中在以上的思想基礎上還涉及了諸多優化)
 2     public static void radixSort(int[] arr,int l,int r) {//res為最大數的位數
 3         if (l < r) {
 4             int res = getRes(arr,l,r);
 5             process(arr,l,r,res);
 6         }
 7     }
 8     
 9     //獲得陣列範圍上的最大數的位數
10     public static int getRes(int[] arr,int l,int r) {
11         int res = 0;
12         int max = Integer.MIN_VALUE;
13         for (int i = l; i <= r; i++) {
14             max = Math.max(max, arr[i]);
15         }
16         while (max != 0) {
17             res++;
18             max /= 10;
19         }
20         return res;
21     }
22     
23     //獲得x的從右到左的第d位
24     public static int getDigit(int x,int d) {
25         return ((x / ((int)Math.pow(10,d - 1))) % 10);
26     }
27     
28     public static void process(int[] arr,int l,int r,int res) {
29         final int radix = 10;//一般都為10進位制數的排序
30         int[] budget = new int[r - l + 1];//用來臨時儲存每輪處理完後的陣列
31         for (int i = 1; i <= res; i++) {//最高位有res位則要進出桶res次,i表示從右到左的第i位
32             int[] count = new int[radix];//用來記錄0-9每種數字出現了幾次(放到迴圈內部重新申請,就不用對前一次
33                                          //得到的陣列進行置0操作)
34             for (int j = l; j <= r; j++) {//記錄當前第i位的0-9的數字的出現次數
35                 int digit = getDigit(arr[j],i);
36                 count[digit]++;
37             }
38             for (int j = 1; j < radix; j++) {//進行字首和處理,得到的字首和結果有 "分片" 的作用
39                 count[j] += count[j - 1];
40             }
41             //關鍵步驟:逆序(可以保證先進先出的思想)通過字首和的分片作用,調整出這輪排序後的結果,存到budget中
42             for (int j = r; j >= l; j--) {
43                 int digit = getDigit(arr[j],i);
44                 budget[--count[digit]] = arr[j];
45             }
46             //將所得的結果budget存回到原陣列arr
47             for (int j = 0; j < budget.length; j++) {
48                 arr[l + j] = budget[j];
49             }
50         }