《排序算法系列7》基數排序(桶排序)

1 思想git

桶排序是計數排序的升級版。它利用了函數的映射關係,高效與否的關鍵就在於這個映射函數的肯定。桶排序 (Bucket sort)的工做的原理:假設輸入數據服從均勻分佈,將數據分到有限數量的桶裏,每一個桶再分別排序(有可能再使用別的排序算法或是以遞歸方式繼續使用桶排序進行排)。算法

2 算法描述數組

  • 設置一個定量的數組看成空桶;
  • 遍歷輸入數據,而且把數據一個一個放到對應的桶裏去;
  • 對每一個不是空的桶進行排序;
  • 從不是空的桶裏把排好序的數據拼接起來。 

3 舉例dom

假設10個數爲:6四、八、21六、5十二、2七、72九、0、一、34二、126函數

第一趟桶式排序(個位):測試

將數組中的每一個數按照個位數字的大小依次存入編號爲0~9的桶,存完以後,從桶中依次取出數據,每一個桶中的數據按照先存入的先取出,後存入的後取出的規則來讀取,而後將讀取的數據存入數組spa

第二趟桶式排序(十位):code

將數組中的每一個數按照位數字的大小依次存入編號爲0~9的桶,存完以後,從桶中依次取出數據,每一個桶中的數據按照先存入的先取出,後存入的後取出的規則來讀取,而後將讀取的數據存入數組orm

第三趟桶式排序(百位):blog

將數組中的每一個數按照百位數字的大小依次存入編號爲0~9的桶,存完以後,從桶中依次取出數據,每一個桶中的數據按照存入的先取出,後存入的後取出的規則來讀取,而後將讀取的數據存入數組

此時發現第三輪事後數組 {0,1,8,27,64,126,216,342,512,729} 已是有序的了,也就獲得咱們想要的結果了

4 基數排序(桶排序)代碼推導

 1   public static void main(String[] args) {
 2         int[] arr = { 58, 3, 542, 748, 14, 214 };
 3         radixSort(arr);
 4   }
 5   // 基數排序方法
 6     public static void radixSort(int[] arr) {
 7         // 第1輪 (針對每一個元素的個位進行排序處理)
 8 
 9         // 定義一個二維數組,表示10個桶,每一個桶都是一個一維數組
10         // 1 二維數組包含10個一維數組
11         // 2爲了防止在放入數的時候,數據溢出,則每個一維數組 大小定義爲arr.length
12         // 3很明確 基數排序用空間換時間的經典算法
13         int[][] bucket = new int[10][arr.length];
14 
15         // 爲了記錄每一個桶中 實際存放了多少個數據 咱們定義一個一維數組 來記錄
16         // 各個桶的每次放入的數據個數
17         int[] bucketElementCounts = new int[10];
18 
19         for (int j = 0; j < arr.length; j++) {
20             // 取出每一個元素的個位的值
21             int digitOfElement = arr[j] / 1 % 10;
22             bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
23             bucketElementCounts[digitOfElement]++;
24         }
25 
26         // 按照這個桶的順序(一位數組的下標 取出數據,放入原理的數據)
27         int index = 0;
28         for (int k = 0; k < bucketElementCounts.length; k++) {
29             // 若是桶中有數據 才放入到原數組
30             if (bucketElementCounts[k] != 0) {
31                 // 循環該桶 即第K個桶 放入
32                 for (int l = 0; l < bucketElementCounts[k]; l++) {
33                     arr[index] = bucket[k][l];
34                     index++;
35                 }
36             }
37             // 第1輪處理後,須要將每一個bucketElementCounts[k] = 0 清零
38             bucketElementCounts[k] = 0;
39         }
40         // [542, 3, 14, 214, 58, 748]
41         System.out.println("第一輪結果" + Arrays.toString(arr));
42 
43         // 第2輪 (針對每一個元素的個位進行排序處理)
44         for (int j = 0; j < arr.length; j++) {
45             // 取出每一個元素的十位的值
46             int digitOfElement = arr[j] / 10 % 10;
47             bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
48             bucketElementCounts[digitOfElement]++;
49         }
50 
51         // 按照這個桶的順序(一位數組的下標 取出數據,放入原理的數據)
52         index = 0;
53         for (int k = 0; k < bucketElementCounts.length; k++) {
54             // 若是桶中有數據 才放入到原數組
55             if (bucketElementCounts[k] != 0) {
56                 // 循環該桶 即第K個桶 放入
57                 for (int l = 0; l < bucketElementCounts[k]; l++) {
58                     arr[index] = bucket[k][l];
59                     index++;
60                 }
61             }
62             bucketElementCounts[k] = 0;
63         }
64         // [3, 14, 214, 542, 748, 58]
65         System.out.println("第二輪結果" + Arrays.toString(arr));
66 
67         // 第3輪 (針對每一個元素的個位進行排序處理)
68         for (int j = 0; j < arr.length; j++) {
69             // 取出每一個元素的百位的值
70             int digitOfElement = arr[j] / 100 % 10;
71             bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
72             bucketElementCounts[digitOfElement]++;
73         }
74 
75         // 按照這個桶的順序(一位數組的下標 取出數據,放入原理的數據)
76         index = 0;
77         for (int k = 0; k < bucketElementCounts.length; k++) {
78             // 若是桶中有數據 才放入到原數組
79             if (bucketElementCounts[k] != 0) {
80                 // 循環該桶 即第K個桶 放入
81                 for (int l = 0; l < bucketElementCounts[k]; l++) {
82                     arr[index] = bucket[k][l];
83                     index++;
84                 }
85             }
86             bucketElementCounts[k] = 0;
87         }
88         // [3, 14, 58, 214, 542, 748]
89         System.out.println("第三輪結果" + Arrays.toString(arr));
90     }

 5 經過循環實現基數排序(桶排序)

 1   public static void main(String[] args) {
 2         int[] arr = { 58, 3, 542, 748, 14, 214 };
 3         radixSort2(arr);
 4   }
 5   public static void radixSort2(int[] arr) {
 6         // 1 獲得數組中最大的數的位數
 7         int max = arr[0];// 假設第一位就是最大數
 8         for (int i = 1; i < arr.length-1; i++) {
 9             if (arr[i] > max) {
10                 max = arr[i];
11             }
12         }
13         // 2 獲得最大數是幾位數
14         int maxLength = (max + "").length();
15 
16         int[][] bucket = new int[10][arr.length];
17         int[] bucketElementCounts = new int[10];
18 
19         for (int i = 0,n = 1; i < maxLength; i++,n *= 10) {
20             for (int j = 0; j < arr.length; j++) {
21                 // 取出每一個元素的個位的值
22                 int digitOfElement = arr[j] / n % 10;
23                 bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
24                 bucketElementCounts[digitOfElement]++;
25             }
26 
27             // 按照這個桶的順序(一位數組的下標 取出數據,放入原理的數據)
28             int index = 0;
29             for (int k = 0; k < bucketElementCounts.length; k++) {
30                 // 若是桶中有數據 才放入到原數組
31                 if (bucketElementCounts[k] != 0) {
32                     // 循環該桶 即第K個桶 放入
33                     for (int l = 0; l < bucketElementCounts[k]; l++) {
34                         arr[index] = bucket[k][l];
35                         index++;
36                     }
37                 }
38                 // 第1輪處理後,須要將每一個bucketElementCounts[k] = 0 清零
39                 bucketElementCounts[k] = 0;
40             }
41             //System.out.println("第" + i + "次排序結果爲" + Arrays.toString(arr));
42         }
43     }

6 時間複雜度

 

7 時間複雜度測試

// 基數(桶)排序
    public static void main(String[] args) {
        speedTest(80000);
    }

    /**
       * 建立一個隨機數組 而後調用排序方法 獲得時間
     * 
     * @param number 建立的隨機數組個數
     */
    public static void speedTest(int number) {
        int[] arr = new int[number];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * 800000);
        }

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date1 = new Date();
        String time1 = simpleDateFormat.format(date1);
        System.out.println("排序前的時間爲:" + time1);

        // 調用上面的基數排序方法
        radixSort2(arr);

        Date date2 = new Date();
        String time2 = simpleDateFormat.format(date2);
        System.out.println("排序後的時間爲:" + time2);
    }

時間複雜度測試結果

8萬個數據測試結果大約不須要1秒

80萬個數據測試結果大約不須要1秒

 800萬個數據測試結果大約不須要1秒

8000萬個數據測試結果會超出虛擬機內存  由於基數排序是典型的拿空間換時間的排序

相關文章
相關標籤/搜索