【基数排序】
基数排序,又称桶排序扩展。属于稳定性排序算法(相同数据在排序过程中前后关系不变)。以{53,3,542,748,14,214}为例:
核心思想是:将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
代码实现:(这里我们不实现负数的排序)
package cn.dataStructureAndAlgorithm.demo.sort;
import java.util.Arrays;
public class 基数排序_RadixSort {
public static void main(String[] args) {
int data[]=new int[]{8,4,5,7,1,3,6,2};
radixSort(data);
System.out.println(Arrays.toString(data));
}
public static void radixSort(int data[]){
//获取数据中最大数
int max=data[0];
for (int i=1;i<data.length;i++){
if (max<data[i]){
max=data[i];
}
}
//获取最大数位数,该位数即基数排序的轮数
int maxSize=(max+"").length();//巧妙算法
//制造桶数组
int[][] bucket=new int[10][data.length];//有可能数据某位全相同,使用没办法只能用data.length
//制造桶计数数组:记录桶中的数据个数
int[] bucketElementCounts=new int[10];
//开始基数排序
for (int i=0,n=1;i<maxSize;i++,n*=10){//循环最高位数次
for (int j=0;j<data.length;j++){//每轮将所有数据都入桶一次
int digit=data[j]/n%10;//求得数据每轮的数位值
bucket[digit][bucketElementCounts[digit]]=data[j];//将数据放入到对应的桶中
bucketElementCounts[digit]++;//计数
}
//把桶中数据按顺序放回原数组
int index=0;//用于操作原数组
for (int k=0;k<10;k++) {
//第k个桶中有数据,就开始放
if (bucketElementCounts[k] != 0) {
//按照桶计数数组中记录的个数,遍历第k个桶
for (int j = 0; j < bucketElementCounts[k]; j++) {
data[index++] = bucket[k][j];//将第k个桶中的全部数据依次放入原数组中
}
}
//一轮处理完成,要把桶计数数组清空
bucketElementCounts[k] = 0;
}
}
}
}
基数排序速度测试:以8000000个【0~8000000】的随机整数为数组,进行速度测试(数据以我电脑为准,本次测速与希尔移位式,快排,归并比较,并将数据量*1000)
希尔移位式式耗时:2s 快速排序耗时:907ms 归并排序耗时:1s 基数排序耗时:487ms
基数排序虽然快,但其产生的内存消耗巨大,80000000的数据量将产生3.3G的内存消耗,是典型的拿空间换时间的算法
优化一:占内存的主要原因在于,以上代码的数据存储结构使用的是数组,而数组的问题在于长度没法改变,为了应付极端状况的出现(某一位数全相同),就必须将数组的以固定长度创建。当待排序的数据超长时,数组也跟着增大。解决方法在于修改数据存储结构,使之应需而变。将其存储结构修改为动态数组,链表这是一种减小内存占用的方法。
优化二:以上代码是基于十进制基数来设计的桶,可否以二进制数据进行桶设计,这样贴近计算机底层,就可以通过移位操作符>>这一种高效率运算来计算2的乘方问题。进一步优化代码
可以参考【这个博客】深入研究。
至此,恭喜你获得【排序小王子】称号
排序算法中还剩下最后一个 堆排序算法 ,在学习了二叉树基础知识与二叉树顺序存储之后,会提到
其他的排序算法有点复杂难懂,我将其另行整理了,可以点击下面的链接进入查找
排序算法_堆排序,该算法需要学习树的知识,可以在下面的目录链接中,自行查找
【数据结构与算法整理总结目录 :>】<-- 宝藏在此(doge)