排序算法--基数排序(RadixSort)的原理、排序过程及代码示例
基数排序(RadixSort)
概念介绍
基于比较排序算法的下界(合并排序,堆排序,快速排序…等)是Ω(nLogn),也就是说,他们不能做得比nLogn更好。
计数排序是一种线性时间排序算法,当元素在1到k的范围内时,以O(n+k)时间排序。
如果元素在1到n2的范围内呢?
这种情况不能使用计数排序,因为计数排序将花费O(n2),这比基于比较的排序算法更差。
如何在线性时间内对这样一个数组进行排序呢?
基数排序(RadixSort)能解决此问题。
基数排序的思想是从最低有效位数到最高有效位数逐个数字排序。基数排序使用计数排序作为子程序进行排序。
基数排序属于桶排序,是一种稳定的排序。
基数排序的发明可以追溯到1887年赫尔曼·何乐礼在打孔卡片制表机(Tabulation Machine)上的贡献。
它是这样实现的:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
基数排序是否优于基于比较的排序算法如快速排序?
如果每个数字都有log2n位,那么对于大范围的输入数字,基数的运行时间似乎比快速排序更好。
基数排序中隐藏的常数因子较高,而快速排序则更有效地使用硬件缓存。
此外,基数排序使用计数排序作为子程序,计数排序占用额外的空间来排序数字。
如针对手机号码排序
排序过程
以给数组 170, 45, 75, 90, 802, 24, 2, 66 排序为例,演示排序过程如下:
- 从低位开始将待排序的数按照这一位的值放到相应的编号为0~9的桶中(计数排序)
- 等到低位排完得到一个子序列,再将这个序列按照次低位的大小进入相应的桶中(计数排序),
- 一直排到最高位为止,数组排序完成
针对数组3,1,18,11,28,45,23,50,30的基数排序过程图解
排序方式
基数排序的两种方式:
高位优先:又称为最有效键(MSD),它的比较方向是由右至左;
低位优先:又称为最无效键(LSD),它的比较方向是由左至右;
复杂度
时间复杂度:
在基数排序中,因为没有比较操作,所以在复杂上,最好的情况与最坏的情况在时间上是一致的,均为 O(d * (n + r))。
其中,d 为位数,r 为基数,n 为原数组个数。
额外空间复杂度:O(n+m)
m 个桶与存放 n 个元素的空间
示例代码
public class RadixSortExample {
public static void main(String[] args) {
int arr1[] = { 170, 45, 75, 90, 802, 24, 2, 66,3,703,43,45 };
radixSort1(arr1, arr1.length);
print(arr1);
int arr2[] = { 170, 45, 75, 90, 802, 24, 2, 66,3,703,43,45 };
radixSort2(arr2,arr2.length);
print(arr2);
}
// A function to do counting sort of arr[] according to the digit represented by exp.
static void countSort(int arr[], int n, int exp, int radix) {
int output[] = new int[n]; // output array
int i;
int count[] = new int[radix];
Arrays.fill(count, 0);
// Store count of occurrences in count[]
for (i = 0; i < n; i++) {
count[(arr[i] / exp) % radix]++;
}
// Change count[i] so that count[i] now contains actual position of this digit in output[]
for (i = 1; i < radix; i++) {
count[i] += count[i - 1];
}
// Build the output array
for (i = n - 1; i >= 0; i--) {
output[count[(arr[i] / exp) % radix] - 1] = arr[i];
count[(arr[i] / exp) % radix]--;
}
// Copy the output array to arr[], so that arr[] now contains sorted numbers according to current digit
for (i = 0; i < n; i++) {
arr[i] = output[i];
}
}
static void radixSort1(int arr[], int n) {
int m = Arrays.stream(arr).max().getAsInt();
int radix = 10;
/**
* Do counting sort for every digit.
* Note that instead of passing digit number, exp is passed.
* exp is 10^i where i is current digit number
*/
for (int exp = 1; m / exp > 0; exp *= radix) {
countSort(arr, n, exp,radix);
}
}
public static void radixSort2(int[] number, int d){
int k = 0;
int n = 1;
int m = 1; //控制键值排序依据在哪一位
int[][]temp = new int[10][number.length]; //数组的第一维表示可能的余数0-9
int[]order = new int[10]; //数组order[i]用来表示该位是i的数的个数
while(m <= d) {
for(int i = 0; i < number.length; i++) {
int lsd = ((number[i] / n) % 10);
temp[lsd][order[lsd]] = number[i];
order[lsd]++;
}
for(int i = 0; i < 10; i++) {
if(order[i] != 0) {
for (int j = 0; j < order[i]; j++) {
number[k] = temp[i][j];
k++;
}
}
order[i] = 0;
}
n *= 10;
k = 0;
m++;
}
}
static void print(int arr[]) {
int n = arr.length;
for (int i = 0; i < n; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
相关文章
- Java实现 蓝桥杯 算法训练 第五次作业:字符串排序
- Java 第十一届 蓝桥杯 省模拟赛 户户通电(图算法)
- Java实现 蓝桥杯 算法提高 快速排序
- Java实现 蓝桥杯VIP 算法训练 会议中心
- Java实现 蓝桥杯 算法训练 排序
- Python实现的选择排序算法原理与用法实例分析
- Python实现的选择排序算法原理与用法实例分析
- 【python cookbook】【数据结构与算法】14.对不原生支持比较操作的对象排序
- 数据结构和算法12 之希尔排序
- C++ <algorithm>Sort()函数秒杀任何常用排序算法
- Jerry 2017年的五一小长假:8种经典排序算法的ABAP实现
- 排序算法 - 快速排序
- ML之Clustering之普聚类算法:普聚类算法的相关论文、主要思路、关键步骤、代码实现等相关配图之详细攻略
- Android 面试算法题 删除排序数组中的重复项和旋转数组
- Android 音频倍速的原理与算法分析
- 【图像处理】基于MATLAB的分形插值算法调换图片
- 图片缩小尺寸算法
- 2.5 Floyd链表查环算法
- 从两个排序算法实现c++策略模式
- 杂文 - [1.1]使用库语言排序算法
- BFS (1)算法模板 看是否需要分层 (2)拓扑排序——检测编译时的循环依赖 制定有依赖关系的任务的执行顺序
- 图解排序算法(三)之堆排序
- 目标检测算法——YOLOv5/YOLOv7改进之结合无参注意力SimAM(涨点神器)
- 排序算法之归并排序
- m基于matlab的polar码误码率仿真,译码算法采用SC算法
- ❤❤算法基础&递归&查找&十大排序算法,献给快要开学的你❤❤
- 排序算法(Learn to rank)的一些看法
- DSA之十大排序算法第六种:Quick Sort
- 【深度强化学习】DDPG算法
- 【递归算法】递归算法的快速入门