桶排序——计数排序和基数排序
桶排序的基本思想:
* 之前所涉及到的简单排序及复杂排序中的归并排序,快速排序和堆排序都属于基于比较的排序
* 而桶排序则是一个不基于比较的排序
*
* 桶排序这类不基于比较的排序的适用范围较为有限
* 其核心思想是把有着相同特点的某些元素装入一个桶,桶与桶之间是有序的,桶的内部也是有序的
* 最终只要按照这种顺序把桶中元素依次倒出即可达到有序
*
* 桶排序适用于已知要排的数组的大致范围,且这个范围不大的情况下,可以使用桶排序来进行
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 }