线性时间排序

线性时间排序

前面写的排序的算法,平均时间复杂度是O(nlogn)的,现在介绍三个线性时间复杂度的排序算法。

一、计数排序

  1. 计数排序:假设n个输入元素位于区间[0,k]之间的元素,k为某个整数,当k=O(n)时,排序的运行时间为O(n)
  2. 基本思想:对于一个输入元素x,确定小于x的元素的个数。就可以直接把x放在相应的位置上。这个排序算法需要使用两个辅助空间,一个用于存放排序的数组,一个用于存放[0,k]的数应该存放的最末位置。每次从A中取出一个数,将其放在排序数组的正确位置。需要传入k的值。
  3. 实现:
  1. publicstaticvoid sort(int[] arr,int k){
  2. int[] tmp =newint[arr.length];
  3. int[] c =newint[k+1];
  4. for(int i =0; i < k +1; i++){
  5. c[i]=0;
  6. }
  7. //计算每个数出现的次数
  8. for(int i =0; i < arr.length; i++){
  9. c[arr[i]]++;
  10. }
  11. //计算每个数应该保存的位置的最后一个(有多个,则c[i]保存的是最后一个i的位置)
  12. for(int i =1; i < k +1; i++){
  13. c[i]= c[i]+ c[i -1];
  14. }
  15. for(int i =0; i < arr.length; i++){
  16. tmp[--c[arr[i]]]= arr[i];
  17. }
  18. for(int i =0; i < arr.length; i++){
  19. arr[i]= tmp[i];
  20. }
  21. }

二、基数排序

  1. 基数排序就是对n个d位的数进行排序,依次从个位、十位、百位、…、d位进行排序,需要10个辅助队列,i存放某位数为i的队列。最终排好序。也可以是对有多个属性(基数)的对象排序,如对日期排序,可以使用年、月、日分别作一次排序,最终达到排序。
  2. 时间复杂度O(d(n+k)),d为位数,n为数组元素个数,k为每一位可能出现的结果(数字为10),当d为常数,k=O(n)时,基数排序是基于线性的排序。这个排序是稳定的排序。
  3. 实现:
  1. publicstaticvoid sort(int[] arr){
  2. if(arr ==null|| arr.length <=0)return;
  3. LinkedList<Integer>[] lists =newLinkedList[10];
  4. for(int i =0; i <10; i++){
  5. lists[i]=newLinkedList<>();
  6. }
  7. int d =1;//第i位
  8. int count =0;//记录当前位为0的个数,如果全部为0,则结束
  9. while(count != arr.length){
  10. count =0;
  11. for(int i =0; i < arr.length; i++){
  12. //计算当前位
  13. int cur =(arr[i]/ d)%10;
  14. if(arr[i]/ d ==0) count++;//说明已经超出该数的位数
  15. lists[cur].addLast(arr[i]);
  16. }
  17. //将数组元素重新排列
  18. int k =0;
  19. for(LinkedList<Integer> list : lists){
  20. for(Integer integer : list){
  21. arr[k++]= integer;
  22. }
  23. list.clear();//清除当前列表
  24. }
  25. d *=10;//下一位
  26. }
  27. }

三、桶排序

  1. 桶排序:假设输入数据服从均匀分布,平均情况下的时间复杂度为O(n),最坏情况是O(n2)。该排序假设输入数据是由一个随机过程生成的,该过程是将元素均匀、独立地分布在[0,1)区间。
  2. 基本思想:桶排序将[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个桶中每个桶里的数字排序,这时可用冒泡,选择,乃至快排,一般来说任何排序法都可以。最后依次输出每个桶里面的数字,且每个桶中的数字从小到大输出,这样就得到所有数字排好序的一个序列了。)
  3. 实现:
  1. publicstaticvoid sort(double[] arr){
  2. if(arr ==null|| arr.length <=0)return;
  3. LinkedList<Double>[] lists =newLinkedList[arr.length];
  4. for(int i =0; i < arr.length; i++){
  5. lists[i]=newLinkedList<>();
  6. }
  7. for(int i=0; i < arr.length; i++){
  8. int index =(int)(arr.length * arr[i]);
  9. lists[index].add(arr[i]);
  10. }
  11. int k =0;
  12. for(LinkedList<Double> list : lists){
  13. Collections.sort(list);//在桶中选择合适的排序算法排序
  14. for(Double aDouble : list){
  15. arr[k++]= aDouble;//将桶中元素插入回原数组。
  16. }
  17. }
  18. }





原文地址:https://www.cnblogs.com/ggmfengyangdi/p/5715213.html