桶排序
-
计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。计数排序不是比较排序,所以他优于任何比较排序。
-
我们将一个数组所有数字出现的次数,统计出来,放入一个辅助数组中,然后把辅助数组中统计的数组从小到大,按每个数出现的次数,有几次输出几次就可以得到一个有序的序列。
图源:https://www.runoob.com/w3cnote/counting-sort.html
例如: 给定一组学生年龄数组,要求给该数组进行计数排序,我们知道年龄的范围是0~200之间,
以下给出python语言的排序代码:
def countingSort(arr,maxValue):
{
#桶的长度是数组中数字最大的数的数值
bucketlen=maxValue+1
#将桶内数组全部置零 用于统计出现次数
bucket = [0]*bucketlen
sorttedIndex=0
arrLen=len(arr)
for i in range(arrlen):
if not bucket[arr[i]]:
bucket[arr[i]]=0
bucket[arr[i]]+=1
for j in range(bucketlen):
while bucket[j]>0:
arr[sorttedIndex]=j
sorttedIndex+=1
bucket[j]-=1
return arr
}
基数排序
- 基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
图源:https://www.runoob.com/w3cnote/radix-sort.html
思考: 准备10个队列(0~9),将每个数字从个位开始,依次放在相应位置上,并且一个“桶中”如果有多个数字,就按先入先出的原则将每个数输出,这样就保证的这一位上的数字依然是从小到大有序的,进而将这种有序性一直传递了下去。
代码算法
利用了一个极其精巧的方式,可以不需要队列完成先入先出的操作。理解起来还是有一点难度的,如下图解释:
以下是以个位数为基准的一次排序过程,完整的过程是分别对个位、十位、百位进行如下的操作:
Java语言描述的代码如下:
//arr[L...R]排序 digit是最大的数字有多少个十进制位,
//也就是最大值的数 位数
public static radixSort(int[] arr,int L,int R,int digit)
{
final int radix=10;
int i=0,j=0;
//有多少个数准备多少个辅助空间
int[] bucket=new int[R-L+1];
//有多少位就操作几次
for(int d=1;d<=digit;d++)
{
int[] count=new int[radix];
for(i=L;i<=R;i++)
{
//得到倒数第d位上的数字是几
j=getDigit(arr[i],d);
count[j]++;
}
//创建count‘数组,count[0]上的数字不变
for(i=1;i<radix;i++)
count[i]=count[i]+count[i-1];
//从右向左遍历arr数组
for(i=R;i>=L;i--)
{
j=getDigit(arr[i],d);
bucket[arr[j]-1]=arr[i];
count[j]--;
}
//把某一位有序的数组copy回原数组
for(i=L,j=0;i<=R;i++,j++)
{
arr[i]=bucket[j];
}
}
}
//返回x这个数在倒数第d位上的数是几
public static int getDigit(int x,int d)
{
return ( ( x/ ( (int)Math.pow(10,d-1) ) ) %10 );
}
//返回最大值的位数
public static int maxbits(int[] arr){
int max=Integer.MIN_VALUE;
for(int i=0;i<arr.length;i++)
{
max=Math.max(max,arr[i]);
}
int res=0;
while(max!=0){
res++;
max/=10;
}
return res;
}
public static void main()
{
int[] arr={022,021,032,001,100}
if(arr==null||arr.length<2){
return;
}
radixSort(arr,0,arr.length-1,maxbits(arr));
}
时间复杂度
O( log(10,max)*N )
max有log(10,max)个十进制位,所以遍历了log(10,max)次数组,数组中共有N个数字。
在计算机中,十进制位有限,所以时间复杂度为O(N)。
不基于比较的排序时间复杂度很小,但是应用的范围很有限。基于排序的比较是比较实用的,应用范围较广。