排序方法可以分为两种:内部排序 和 外部排序
内部排序的方法很多,常用的大致可以分为:
基本思想:与之前各种排序算法需要比较和移动不同,基数排序不需要比较,只通过关键字分类来完成排序。
比如一个序列有 n 个数据 {R1,R2,R3,…,Rn},每个数据含有 k 个关键字 Ri = (Ai,Bi,Ci,Di…),对其排序需要分别考虑 k 个关键字。比如定义一个整型数组,元素的每一位都可以看成一个关键字。
<span style="font-size:18px;">int[] array = { 49, 38, 65, 97, 76, 13, 27, 49, 78, 34, 12, 64, 5, 4};</span>首先建立一个二维数组:
0 | ||||
1 | ||||
2 | ||||
3 | ||||
4 | ||||
5 | ||||
6 | ||||
7 | ||||
8 | ||||
9 |
先对array按照个位(第一个关键字)分类,放入数组中:
0 | ||||
1 | ||||
2 | 12 | |||
3 | 13 | |||
4 | 34 | 64 | 4 | |
5 | 65 | 5 | ||
6 | 76 | |||
7 | 97 | 27 | ||
8 | 38 | 78 | ||
9 | 49 | 49 |
<span style="font-size:18px;">array = { 12,13,34,64,4,65,5,76,97,27,38,78,49,49};</span>
接着对数组中的十位(第二个关键字)进行分类:
0 | 4 | 5 | ||
1 | 12 | 13 | ||
2 | 27 | |||
3 | 34 | 38 | ||
4 | 49 | 49 | ||
5 | ||||
6 | 64 | 65 | ||
7 | 76 | 78 | ||
8 | ||||
9 | 97 |
<span style="font-size:18px;">array = { 4,5,12,13,27,34,38,49,49,64,65,76,78,97};</span>同时也能看出,基数分类是稳定的。
Java代码:
public class RadixSort { public static int[] sort(int[] s) { int[][] bucket = new int[10][s.length];// 二维数组分类存放,行:0 ~ 9,列:存放对应该位的数的个数 int n = 1;// 获取某一位,从最低位开始 int[] col = new int[s.length];// 存放当前位 的 数字 的 个数,即二维数组在这一行的列数 int count = 1;// 按照每一位排序,排序次数计数 int k = 0;// 保存每一位排序后的结果到数组 s 中,用于下一位的排序输入 int digit_num = RadixSort.getMaxDigit(s);// 获取数列中最多的位数,并以此为准 while (count <= digit_num) { for (int num : s) {// 将s中的数据根据当前digit分类,存入bucket数组中 int digit = (num / n) % 10; bucket[digit][col[digit]] = num; col[digit]++; } for (int i = 0; i < s.length; i++) {// 依次遍历bucket的每一行 if (col[i] != 0) {// 当前行的数据不为0 for (int j = 0; j < col[i]; j++) {// 将当前行的数据更新到数组s中 s[k] = bucket[i][j]; k++; } } col[i] = 0;// 要把当前列数清零 } n *= 10; count++; k = 0; } return s; } // 静态方法中不能调用非静态方法 private static int getMaxDigit(int[] s) { int d = 1; int max = 0; for (int i = 0; i < s.length; i++) { if (s[i] > max) max = s[i]; } while (max / 10 != 0) { d++; max = max / 10; } return d; } }
基数排序的时间复杂度是O(k·n),其中n是排序元素个数,k是数字位数。
k的大小取决于数字位的选择(比如比特位数),和待排序数据所属数据类型的全集的大小;k决定了进行多少轮处理,而n是每轮处理的操作数目。