zoukankan      html  css  js  c++  java
  • 几种常见的排序算法总结

    *****选择排序*****

    方法描述:首先找到第一个最小的数,和第一个数交换;然后从剩下的找出最小的与第二个交换,以此类推。
    效率: 长度为N的数组,大约N2/2比较,N次交换
    特点: 1.运行时间和输入无关,有序数组,全部相等的数组,随机数组所用时间一样,没有充分利用输入的初始状态。
        2.数据移动最少,与输入成线性关系。
    代码

    sort(int[] a){
      int n = a.length;
      for(int i = 0; i < n; i++){
        int min = i;
         for(int j = i; j < n; j++){
          if(a[j] < a[i])
            swap(a[i],a[j]);
         }
      }
     }

    *****插入排序*****


    背景:打扑克牌
    方法描述:后面的数插入到前面已经有序的子数组中
    效率: 平均移动一半元素,所以N2/4次比较和交换;最坏N2/2次比较和交换;最好 N-1 次比较和0次交换
    特点: 对于部分有序的数组效率非常高,时间是线性级别的。
      几个典型的部分有序数组:数组中每个元素距离它的最终位置不远;一个有序的大数组接一个小数组;数组中只有几个元素的位置不正确;
    代码:

    sort(int[] a){
      int n = a.length;
      for(int i = 1; i < n; i++){
        for(int j = i-1; j >= 0 && a[j] < a[i]; j--){
          swap(a[i],a[j]);
        }
      }
    }

    *****希尔排序*****


    背景:大规模的插入排序效率很低,因为它仅仅交换相邻的元素。希尔排序的思想就是:对大数组中间隔为h的子数组排序,将数组大约分成
    h个间隔为h的子数组,并逐渐减小h,h=1时其实就是插入排序。这样做的好处是,排序之初,只对间隔为h的子数组排序,排序规模小,速度快;
    随着h的减小,数组趋于有序,此时插入排序能充分发挥作用。
    方法描述:后面的数插入到前面已经有序的子数组中
    效率: 平均移动一半元素,所以N2/4次比较和交换;最坏N2/2次比较和交换;最好 N-1 次比较和0次交换
    特点: 对于部分有序的数组效率非常高,时间是线性级别的。
    代码

    sort(int[] a){
      int n = a.length;
      int h = 1;
      while(h < N/3) h = 3*h+1;
      while(h >= 1){
        for(int i = h; i < n; i++){
          for(int j = i; j >= 0 && a[j] < a[i]; j -= h){
            swap(a[j],a[i]);
          }
        }
        h = h/3;
      }  
    }

    *****归并排序*****


    方法描述:归并思想
    效率: NlogN
    (1)原地归并代码:

    public static void merge(int[] a, int lo, int mid, int hi){
      int i = lo, j = mid+1;
      int[] aux = new int[a.length];
      for(int k = lo; k <= hi; k++){
        aux[k] = a[k];
      }
      for(int k = lo; k <= hi; k++){
        if(i > mid) a[k] = aux[j++];//异常情况一定要放前面,不然可能导致数组越界,报空指针异常
        else if(j > hi) a[k] = aux[i++];
        else if(a[i] < a[j]) a[k] = aux[i++];
        else a[k] = aux[j++];
      }
    }
    排序:

    sort(int[] a, int lo, int hi){
      if(hi < lo) return;
      int mid = lo + (hi -lo)/2;
      sort(a,lo,mid);
      sort(a,mid+1,hi);
      merge(a,lo,mid,hi);
    }

    改进:1.小规模用插入排序
       2. 测试数组是否有序, a[mid] < a[mid+1] 就认为有序,就跳过merge方法,这样能使得有序的
        子数组时间降为线性。

    (2)自底向上归并排序:
    方法:先两两归并,再44归并,再88,。。。。。
    代码
    sort(int[] a){
      int n = a.length;
      aux = new int[n];
      for(int i = 1; i < n; i += i+i){
        for(int j = 0; j< n-i; j+= i+i){
          merge(a,j,j+i-1,Math.min(j+i+i-1,n-1));
        }
      }
    }
    特点:适合链表组织的数据,只需要重新组织链表链接就能将链表原地排序。

    *****快速排序*****


    特点:原地排序; nlogn; 内循环小,比较次数少,而且是和固定值进行比较,所以非常快. 例如归并,插入排序,都会在内循环中移动元素,所以慢
       和归并排序相比:归并是递归在前,处理数组在后;快排相反
    代码:
    public static void sort(int[] a, int lo,int hi){
      if(hi < lo) return;
      int j = partition(a,lo,hi);
      sort(a,lo,j-1);
      sort(a,j+1,hi);
    }
    static partition(int[] a, int lo, int hi){
      int i = lo, j = hi+1;
      int guard = a[lo];
      while(true){
        while(a[++i] < guard) if(i == hi) break;
        while(a[--j] > guard) if(j == lo) break;
        if(i >= j) break;
        swap(a[i],a[j]);
      }
      swap(a[lo],a[j]);
      return j;
    }
    改进:基于插入排序对于小数组更加高效这一特点。
    1. if(hi <= lo) return -> if(hi <= lo+M) {Insertion.sort(a,lo,hi); return;}

  • 相关阅读:
    java通过ST4使用模板字符串
    使用 docker创建redis实例并且连接
    Docker 认证成功后还是无法push构建好的镜像
    记录一次在openwrt中折腾docker
    全局模式、PAC模式、直连模式的区别
    Vue Router中调用this.$router.push() 时,location使用path无法传入params
    liunx之系统
    liunx之通配符&正则表达式
    liunx之基础
    liunx之find命令
  • 原文地址:https://www.cnblogs.com/zhanht/p/5721540.html
Copyright © 2011-2022 走看看