线性时间排序
前面写的排序的算法,平均时间复杂度是O(nlogn)的,现在介绍三个线性时间复杂度的排序算法。
一、计数排序
- 计数排序:假设n个输入元素位于区间[0,k]之间的元素,k为某个整数,当k=O(n)时,排序的运行时间为O(n)
- 基本思想:对于一个输入元素x,确定小于x的元素的个数。就可以直接把x放在相应的位置上。这个排序算法需要使用两个辅助空间,一个用于存放排序的数组,一个用于存放[0,k]的数应该存放的最末位置。每次从A中取出一个数,将其放在排序数组的正确位置。需要传入k的值。
- 实现:
publicstaticvoid sort(int[] arr,int k){
int[] tmp =newint[arr.length];
int[] c =newint[k+1];
for(int i =0; i < k +1; i++){
c[i]=0;
}
//计算每个数出现的次数
for(int i =0; i < arr.length; i++){
c[arr[i]]++;
}
//计算每个数应该保存的位置的最后一个(有多个,则c[i]保存的是最后一个i的位置)
for(int i =1; i < k +1; i++){
c[i]= c[i]+ c[i -1];
}
for(int i =0; i < arr.length; i++){
tmp[--c[arr[i]]]= arr[i];
}
for(int i =0; i < arr.length; i++){
arr[i]= tmp[i];
}
}
二、基数排序
- 基数排序就是对n个d位的数进行排序,依次从个位、十位、百位、…、d位进行排序,需要10个辅助队列,i存放某位数为i的队列。最终排好序。也可以是对有多个属性(基数)的对象排序,如对日期排序,可以使用年、月、日分别作一次排序,最终达到排序。
- 时间复杂度O(d(n+k)),d为位数,n为数组元素个数,k为每一位可能出现的结果(数字为10),当d为常数,k=O(n)时,基数排序是基于线性的排序。这个排序是稳定的排序。
- 实现:
publicstaticvoid sort(int[] arr){
if(arr ==null|| arr.length <=0)return;
LinkedList<Integer>[] lists =newLinkedList[10];
for(int i =0; i <10; i++){
lists[i]=newLinkedList<>();
}
int d =1;//第i位
int count =0;//记录当前位为0的个数,如果全部为0,则结束
while(count != arr.length){
count =0;
for(int i =0; i < arr.length; i++){
//计算当前位
int cur =(arr[i]/ d)%10;
if(arr[i]/ d ==0) count++;//说明已经超出该数的位数
lists[cur].addLast(arr[i]);
}
//将数组元素重新排列
int k =0;
for(LinkedList<Integer> list : lists){
for(Integer integer : list){
arr[k++]= integer;
}
list.clear();//清除当前列表
}
d *=10;//下一位
}
}
三、桶排序
- 桶排序:假设输入数据服从均匀分布,平均情况下的时间复杂度为O(n),最坏情况是O(n2)。该排序假设输入数据是由一个随机过程生成的,该过程是将元素均匀、独立地分布在[0,1)区间。
- 基本思想:桶排序将[0,1)区间划分为n个相同大小的的子区间,或称为桶。然后将n个输入分别放入各个桶中。假设输入数组为n个元素的数组A,0≤A[i]<1,需要一个辅助数组B存放链表。可以将排序扩展(例如要对大小为[1..1000]范围内的n个整数A[1..n]排序,可以把桶设为大小为10的范围,具体而言,设集合B[1]存储[1..10]的整数,集合B[2]存储(10..20]的整数,……,集合B[i]存储((i-1)×10, i×10]的整数,i = 1,2,..100。总共有100个桶。然后对A[1..n]从头到尾扫描一遍,把每个A[i]放入对应的桶B[j]中。 然后再对这100个桶中每个桶里的数字排序,这时可用冒泡,选择,乃至快排,一般来说任何排序法都可以。最后依次输出每个桶里面的数字,且每个桶中的数字从小到大输出,这样就得到所有数字排好序的一个序列了。)
- 实现:
publicstaticvoid sort(double[] arr){
if(arr ==null|| arr.length <=0)return;
LinkedList<Double>[] lists =newLinkedList[arr.length];
for(int i =0; i < arr.length; i++){
lists[i]=newLinkedList<>();
}
for(int i=0; i < arr.length; i++){
int index =(int)(arr.length * arr[i]);
lists[index].add(arr[i]);
}
int k =0;
for(LinkedList<Double> list : lists){
Collections.sort(list);//在桶中选择合适的排序算法排序
for(Double aDouble : list){
arr[k++]= aDouble;//将桶中元素插入回原数组。
}
}
}