基數排序是一種非比較型整數排序算法,其原理是將整數按位數切割成不一樣的數字,而後按每一個位數分別比較。因爲整數也能夠表達字符串(好比名字或日期)和特定格式的浮點數,因此基數排序也不是隻能使用於整數。javascript
基數排序(radix sort)屬於「分配式排序」(distribution sort),又稱「桶子法」(bucket sort)或bin sort,顧名思義,它是透過鍵值的部份資訊,將要排序的元素分配至某些「桶」中,藉以達到排序的做用,基數排序法是屬於穩定性的排序,其時間複雜度爲O (nlog(r)m),其中r爲所採起的基數,而m爲堆數,在某些時候,基數排序法的效率高於其它的穩定性排序法。php
將全部待比較數值(正整數)統一爲一樣的數位長度(最大元素長度),數位較短的數前面補零。html
從最低位開始,依次進行一次排序。 java
重複操做,直至完成最高位的排序。mysql
時間複雜度爲:k* length;其中 k爲數組元素最高位數,length爲元素個數;故時間複雜度爲O(K*N)。git
在基數排序中,由於沒有比較操做,因此在複雜上,最好的狀況與最壞的狀況在時間上是一致的。所以不管是最好,最壞仍是平均複雜度都是O(d * (n + r))。其中,d 爲位數,r 爲基數,n 爲原數組個數。 算法
設待排序列爲n個記錄,d個關鍵碼,關鍵碼的取值範圍爲radix,則進行鏈式基數排序的時間複雜度爲O(d(n+radix)),其中,一趟分配時間複雜度爲O(n),一趟收集時間複雜度爲O(radix),共進行d趟分配和收集。 空間效率:須要2*radix個指向隊列的輔助空間,以及用於靜態鏈表的n個指針。sql
空間複雜度O(n+dr)數組
穩定的算法。數據結構
不能歸位
普通正整數
import java.util.ArrayList; import java.util.List; public class RadixSort { /** * MSD方法1--兩個數組,基於計數排序 * @param arr */ public static void radixSortMSD(int[] arr) { int exp; // 指數。當對數組按各位進行排序時,exp=1;按十位進行排序時,exp=10;... int max = getMax(arr); //最大值 int maxDigit = maxDigit(max);//最大數位 for (exp = (int) Math.pow(10, maxDigit-1); exp >1 ; exp /= 10){//高位->低位 countingSort(arr, exp); } } /** * LSD 方法1--兩個數組,基於計數排序 * @param arr */ public static void radixSort(int[] arr) { int exp; // 指數。當對數組按各位進行排序時,exp=1;按十位進行排序時,exp=10;... int max = getMax(arr);// 數組arr中的最大值 for (exp = 1; max/exp > 0; exp *= 10){//低位->高位 countingSort(arr, exp); } } public static void countingSort(int[]arr, int exp){ int[] output = new int[arr.length]; // 存儲"被排序數據"的臨時數組 int[] buckets = new int[10]; // 將數據出現的次數存儲在buckets[]中 for (int i = 0; i < arr.length; i++){ buckets[ (arr[i]/exp)%10 ]++; } // 更改buckets[i]。目的是讓更改後的buckets[i]的值,是該數據在output[]中的位置。 for (int i = 1; i < 10; i++) buckets[i] += buckets[i - 1]; // 將數據存儲到臨時數組output[]中 for (int i = arr.length - 1; i >= 0; i--) { output[buckets[ (arr[i]/exp)%10 ] - 1] = arr[i]; buckets[ (arr[i]/exp)%10 ]--; } // 將排序好的數據賦值給a[] for (int i = 0; i < arr.length; i++){ arr[i] = output[i]; } } /** * LSD 方法2--二維數組 * @param arr */ public static void radixSort2(int[] arr) { int maxDigit = maxDigit(getMax(arr)); int digitValue=1;//表明位數對應的數:1,10,100... int RADIX = 10; int length=arr.length; int[][] bucket=new int[RADIX][length];//排序桶用於保存每次排序後的結果,這一位上排序結果相同的數字放在同一個桶裏 int[] order=new int[RADIX];//用於保存每一個桶裏有多少個數字 while(digitValue < Math.pow(RADIX, maxDigit+1)) { for(int num:arr) { //將數組arr裏的每一個數字放在相應的桶裏 int digit=(num/digitValue)%RADIX; bucket[digit][order[digit]]=num; order[digit]++; } int k=0;//保存每一位排序後的結果用於下一位的排序輸入 for(int i=0;i<RADIX;i++) {//將前一個循環生成的桶裏的數據覆蓋到原數組中用於保存這一位的排序結果 if(order[i]!=0) {//這個桶裏有數據,從上到下遍歷這個桶並將數據保存到原數組中 for(int j=0;j<order[i];j++) { arr[k++]=bucket[i][j]; } } order[i]=0;//將桶裏計數器置0,用於下一次位排序 } digitValue*=RADIX; } } /** * LSD 方法3--數組列表 * @param arr */ public static void radixSort3(int[] arr) { int maxDigit = maxDigit(getMax(arr)); List<List<Integer>> list = new ArrayList<List<Integer>>(); for(int i = 0; i < 10; i ++) { list.add(new ArrayList<Integer>()); } for(int i = 0, factor = 1; i < maxDigit; factor *= 10, i ++) { for(int j = 0; j < arr.length; j ++) { list.get((arr[j]/factor)%10).add(arr[j]); } for(int j = 0, k = 0; j < list.size(); j ++) { while(!list.get(j).isEmpty()) { arr[k] = list.get(j).get(0); list.get(j).remove(0); k ++; } } } } /** * LSD 方法4--隊列 * @param arr */ public static void radixSort4(int[] arr) { //求最大位數 int count = maxDigit(getMax(arr)); int len = arr.length; //十個隊列,分別存儲數位數值爲0-9的元素 BucketQueue [] queues = new BucketQueue[10]; //各隊列初始化 for(int i = 0; i < 10; i++) { queues[i] = new BucketQueue(); queues[i].data = new int[len]; queues[i].front = queues[i].rear = -1; } int m = 1;//m控制取第幾位(從個位開始取直到count) while(count > 0) { for(int i = 0; i < len; i++) { int t = arr[i] / m % 10; //根據數值分配入隊 queues[t].data[++queues[t].rear] = arr[i]; } //從隊號0-9順序出隊收集元素 int s = 0; for(int j = 0; j < 10; j++) { while(queues[j].front != queues[j].rear) { arr[s++] = queues[j].data[++queues[j].front]; } //收集後隊列清空,方便下一趟排序 queues[j].front = queues[j].rear = -1; } m *= 10; count--; } } /** * 獲取數組arr中最大值 */ private static int getMax(int[] arr) { int max; max = arr[0]; for (int i = 1; i < arr.length; i++){ if (arr[i] > max){ max = arr[i]; } } return max; } //計算數組裏元素的最大位數 private static int maxDigit(int max) { if (max == 0) { return 1; } int lenght = 0; for (int temp = max; temp != 0; temp /= 10) { lenght++; } return lenght; } public static void main(String[] args) { int[] A=new int[]{73,22, 93, 43, 55, 14, 28, 65, 39, 81}; radixSortMSD(A); for(int num:A) { System.out.println(num); } } } class BucketQueue { int data[]; int front; int rear; }
字符串
public class RadixSort { public static void main(String[] args) { String[] words = {"Java", "Mongodb", "Redis", "Kafka", "javascript", "mysql", "mybatis", "kindle", "rpc", "Algorithm", "mergeSort", "quickSort", "Adobe"}; radixSort(words); for (String word : words) { System.out.println(word.replaceAll("0", "")); } } //基數排序(單詞 private static void radixSort(String[] words){ int exp = 0; int maxLength = getMaxLength(words); autoComplete(words, maxLength); for(exp = 1; exp <= maxLength; exp++){ countingSort(words, exp); } } //計數排序(單詞) private static void countingSort(String[] words, int exp){ int n = words.length; String[] r = new String[n]; int[] c = new int[122]; for(int i = 0; i < n; ++i){ int asc = (byte)words[i].charAt(words[i].length() - exp); c[asc]++; } for(int i = 1; i < 122; ++i){ c[i] = c[i-1] + c[i]; } for (int i = n - 1; i >= 0; --i){ int asc = (byte)words[i].charAt(words[i].length() - exp); int index = c[asc]; r[index - 1] = words[i]; c[asc]--; } for(int i = 0; i < n; ++i){ words[i] = r[i]; } } //自動補全單詞 private static void autoComplete(String[] words, int maxLength){ int i = 0; for (String word : words) { if(word.length() < maxLength){ int value = maxLength - word.length(); StringBuilder sb = new StringBuilder(); for(int j = 0; j < value; ++j){ sb.append("0"); } words[i] = word + sb; } i++; } } //獲取字符串最大的長度 private static int getMaxLength(String[] words){ int maxLength = words[0].length(); for(int i = 1; i < words.length; ++i){ if(words[i].length() > maxLength) maxLength = words[i].length(); } return maxLength; } }