zoukankan      html  css  js  c++  java
  • 线性时间排序

    线性时间排序

    前面写的排序的算法,平均时间复杂度是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. }





  • 相关阅读:
    VS2015生成64位dll文件
    gdb简单调试~core文件
    Ubuntu ENet 的下载和编译
    Android LIstView初次创建getview方法执行多次问题
    android ipc通信机制之之三,进程通讯方式。
    Android Stduio统计项目的代码行数
    Android开发遇到的坑(1):Java中List的安全删除问题
    Android Studio修改项目的包名
    类似IOS的滑动返回上一级,SwipeBackLayout-android的滑动返回类库
    [转]理解RESTful架构
  • 原文地址:https://www.cnblogs.com/ggmfengyangdi/p/5715213.html
Copyright © 2011-2022 走看看