幾種常見的排序算法總結

*****選擇排序*****數組

方法描述:首先找到第一個最小的數,和第一個數交換;而後從剩下的找出最小的與第二個交換,以此類推。
效率: 長度爲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]);
     }
  }
 }

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


背景:打撲克牌
方法描述:後面的數插入到前面已經有序的子數組中
效率: 平均移動一半元素,因此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;
  }  
}

*****歸併排序*****it


方法描述:歸併思想
效率: NlogN
(1)原地歸併代碼:io

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;}

相關文章
相關標籤/搜索