【校招VIP】数据结构(Java):排序算法之基数排序(又称桶排序)

20小时前 收藏 0 评论 0 java开发

【校招VIP】数据结构(Java):排序算法之基数排序(又称桶排序)

转载声明:文章来源https://blog.csdn.net/qq_51066068/article/details/123841545


基数排序(又称桶子法):

基本思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

计数排序的原理:就是用一个数组来统计每种数字出现的次数,然后按照大小顺序将其依次放回原数组,达成排序的目的。

但是计数排序有一个很严重的问题,就是其只能对整数进行排序,一旦遇到字符串时,就无能为力了。

为了弥补上述的缺点,针对于字符串的基数排序诞生了。

基数排序在计数排序的基础上进行了改进,将排序工作拆分为多个阶段,每一个阶段只根据一个字符进行排序,一共排序K轮(K为数据长度)

基数排序是属于稳定性的排序,基数排序是效率高且稳定的

基数排序是桶排序的扩展

基数排序(桶排序):

适合于有不同位数的大小数字,例如以下数列:

核心思想是:

属于分配式排序,先找十个桶:0~9,每一个数字是一个桶子

第一轮按照元素的个位数排序

桶内分别存放上述数组元素的个位数,按照数组元素的顺序依次存放

之后,按照从左向右,从上到下的顺序(这样是保证排列有序)依次取出元素,组成新的数组。

在新的数组中,进行第二轮,按照十位数排序,依次存放于桶中:

按照从左向右,从上到下的顺序(这样是保证排列有序)依次取出元素,再次组成新的数组。

进行第三轮,按照百位数排序:

将百位数的元素取出之后,我们发现新的数组已经变成了有序数组


代码实现:

为什么不能用一维数组,一定要用二维数组这样的类似桶的结构来存储中间位排序结果?其实之所以要写这个问题,是因为我觉得这个问题是理解基数排序的关键。基数排序本身原理很简单,但是实现中有两个问题需要考虑:1.怎么保留前一位的排序结果,这个问题用之前提到的排序稳定性可以解决。2.怎么关联该位排序结果和原数组元素,二维数组正是为了解决这个问题使用的办法。在计数排序里,虽然保留了所有相等的元素的相对位置,但是这些相等的元素在计数排序里实际是没有差别的,因此我们可以只保存数组里有多少个这样的元素即可。而基数排序里不同,有些元素虽然在某一位上相同,但是他们其他位上很可能不同,如果只保存该位上有多少个5或者多少个6,那关于元素其他位的信息就都丢弃了,这样也就没法对这些元素更高位进行排序了。

public class RadixSort {
private static void radixSort(int[] array,int d)
{
int n=1;//代表位数对应的数:个1,十10,百100...
int k=0;//保存每一位排序后的结果用于下一位的排序输入
int length=array.length;//获取形参传入数组的长度
//这里用的二维数组
int[][] bucket=new int[10][length];//排序桶用于保存每次排序后的结果,这一位上排序结果相同的数字放在同一个桶里
int[] order=new int[length];//用于保存每个桶里有多少个数字
while(n<d)
{
//这里面需要想象力想象存储过程,小伙伴们可以自己在草稿本上画一下
for(int num:array) //将数组array里的每个数字放在相应的桶里
{
int digit=(num/n)%10; //第一轮获每个数的取个位,第二轮十位数字,第三轮千位数字.....
bucket[digit][order[digit]]=num; //digit:横排从左到右,从大到小第几个桶子 order[digit]:列,桶子里存储的数
order[digit]++;//桶子移到下一个位置为存储下一个数字做准备
}
for(int i=0;i<length;i++)//从第一个桶子开始查找,将前一个循环生成的桶(就是二维数组内对应列里的值)里的数据覆盖到原数组中用于保存这一位的排序结果
{
if(order[i]!=0)//这个桶里有数据,从上到下遍历这个桶并将数据保存到原数组中
{
for(int j=0;j<order[i];j++)
{
array[k]=bucket[i][j];//将二维数组里面存放的数值保存到原数组
k++;
}
}
order[i]=0;//将桶里计数器置0,用于下一次位排序
}
n*=10;
k=0;//将k置0,用于下一轮保存位排序结果
}

}
public static void main(String[] args)
{
int[] A=new int[]{73,22, 93, 43, 55, 14, 28, 65, 39, 81};
radixSort(A, 100);
for(int num:A)
{
System.out.print(num+" ");
}
}
}


算法分析

1、基数排序的性能

其中,d代表数组元素最高为位数,n代表元素个数。

2、时间复杂度

这个时间复杂度比较好计算:count * length;其中 count 为数组元素最高位数,length为元素个数;所以时间复杂度:O(n * d)

3、空间复杂度

空间复杂度是使用了两个临时的数组:10 + length;所以空间复杂度:O(n)。

4、算法稳定性

在基数排序过程中,每次都是将当前位数上相同数值的元素统一“装桶”,并不需要交换位置。所以基数排序是稳定的算法。

C 0条回复 评论

帖子还没人回复快来抢沙发