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萬個數據測試結果會超出虛擬機內存 由於基數排序是典型的拿空間換時間的排序