# 算法 - 基数排序

 1 import java.util.Random;
2
3 public class RadixSort {
4
5     public void sort(int arr[]) {
6         int max = arr[0];
7         for (int i = 1; i < arr.length; i++) {
8             if (arr[i] > max) {
9                 max = arr[i];
10             }
11         }
12         // 计数
13         int[] bucketArr;
14         // 输出
15         int[] outputArr = new int[arr.length];
16         // 根据最大值求指数
17         int exp = (int) Math.pow(10, String.valueOf(max).length() - 1);
18         for (int i = 1; i <= exp; i *= 10) {
19             bucketArr = new int[10];
20             for (int j = 0; j < arr.length; j++) {
21                 int index = arr[j] / i % 10;
22                 bucketArr[index]++;
23             }
24             printArr(bucketArr, " => 计数bucket");
25             // 转换 => 见转换说明
26             for (int j = 1; j < 10; j++) {
27                 bucketArr[j] += bucketArr[j - 1];
28             }
29             printArr(bucketArr, " => 转换bucket");
30             // 根据转换后的bucket数组，将原数组的值映射到output数组 => 见映射说明
31             // 注意采用的是倒序遍历 => 见倒序说明
32             for (int j = arr.length - 1; j >= 0; j--) {
33                 int index = arr[j] / i % 10;
34                 int outputIndex = bucketArr[index]--;
35                 outputArr[outputIndex - 1] = arr[j];
36             }
37             printArr(outputArr," => output数组");
38             for (int j = 0; j < outputArr.length; j++) {
39                 arr[j] = outputArr[j];
40             }
41         }
42     }
43
44     private void printArr(int[] arr, String message) {
45         for (int n : arr) {
46             System.out.print(n + ",");
47         }
48         System.out.println(message);
49     }
50
51     public static void main(String[] args) {
52         int capacity = 10;
53         int[] arr = new int[capacity];
54         for (int i = 0; i < capacity; i++) {
55             arr[i] = new Random().nextInt(500);
56         }
58         rs.printArr(arr, " => 原数组");
59         rs.sort(arr);
60         rs.printArr(arr, " => 排序后数组");
61     }
62
63     /**
64      * 转换说明：
65      * 0,1,0,0,2,4,0,2,1,0, => 计数bucket
66      * 转换公式：bucekt[i] += bucket[i - 1]
67      * 0,1,1,1,3,7,7,9,10,10, => 转换bucket
68      * 说白了就是为了统计到[i]位置，bucket获取的元素数
69      *
70      * 映射说明：
71      * 45,5,21,245,454,204,138,137,77,445, => 原数组
72      * 0,1,1,1,3,7,7,9,10,10, => 转换bucket
73      * 当前的exp是1：
74      * 首先计算原数组中的值在bucket哪个位置：=> index = 445 / 1 % 10 = 5
75      * 找到bucket[5]对应的值是7，7代表的是个数，因此要减去1才代表下标。
76      * out[6] = 445
77      * 21,454,204,45,5,245,445,137,77,138, => output数组
78      *
79      * 倒序说明：
80      * 204,5,21,137,138,45,245,445,454,77, => 按照十位已经排好序了
81      * 此时，数组十位是有序状态，【从小到大】。
82      * 4,2,2,0,2,0,0,0,0,0, => 计数bucket => 其中5,21,45,77在0坐标处计数，为4
83      * 4,6,8,8,10,10,10,10,10,10, => 转换bucket
84      * 求百位时，所有的个位和十位在求对应的bucket位置时都是0。
85      * 如果按正序遍历，就相当于按照从大到小的顺序填入output数组。
86      * 如正序遍历，拿到5，求得bucket坐标是0，读取值4，坐标为3，output[3]=5，读取值-1
87      * 继续遍历到21，求得bucket坐标是0，读取值3，坐标为2，output[2]=21，读取值-1
88      * 顺序反了，因此需要倒序遍历。
89      *
90      * 利用空间换时间，但是利用了转换规则，使空间开销较小
91      * => 遍历了exp * (4m + 10) 次
92      * => 时间复杂度O(n) => exp还是有限的
93      * => 稳定性：稳定 => 都是整数
94      *
95      */
96
97 }

posted @ 2020-04-30 16:42  SamNicole1809  阅读(97)  评论(0编辑  收藏