算法導論筆記 第7章 快速排序

快速排序是用於排序的最佳使用選擇,這是由於其平均性能至關好,指望運行時間是O(nlgn),且記號中隱藏的常數因子很小。另外:它還可以進行就地排序。算法

快速排序是基於分治模型的:數組

  1. 分解:數組A[p..r)被劃分紅兩個(可能爲空)子數組A[p..q)和A[q+1..r),使得A[p..q)中的每一個元素都小於A[q], 並且,小於等於A[q+1..r)中的元素。下標q也在這個劃分過程當中進行計算。
  2. 解決:經過遞歸調用快排程序,對子數組A[p.q)和A[q+1..r)進行排序。
  3. 合併:由於兩個子數組是就地排序的,將它們合併不須要操做:整個A[p..r)已經排序。

 

void quicksort(int* A, int p, int r){
  if (p < r) {
    int q = partition(A, p, r);
    quicksort(A, p, q);
    quicksort(A, q+1, r);
  }
}

爲排序一個完整的數組A,最初的調用是quicksort(A, 0, __count_of(A) )dom

 

快排算法的關鍵是PARTITION過程,它對子數組A[p...r)進行就地重排 函數

int  partition(int*  A, int p, int r) {
  int x = A[r -1];
  int i = p - 1;
  int j = p;
  for (; j < r-1; j++) {
    if (A[j] <=x) {
      i++;
      int tmp = A[i]; A[i] = A[j]; A[j] = tmp;// A[i]  A[j]
    }
  }
  i++;
  int tmp = A[i]; A[i] = A[j]; A[j] = tmp;// A[i]  A[j]
  return i;
}

能夠用循環不變式來分析一下Partition程序:性能

循環不變量是.任何在[p,i]的數都小於等於x, 在[i,j)的數都大於x。 在[j,r)的數未知。 A[r-1] = X。ui

  1. 初始化:在循環的第一輪迭代開始以前,i = p-1, j=p。 在p與i之間沒有值。在i+1與和j-1之間也沒有值,且x = A[r -1]  所以知足循環不變式。
  2. 保持:當A[j]>x時,循環惟一的操做是j++. j自加後知足在[i,j)的數都大於x。且其它全部項保持不變。  當A[j]<=x時,自加i, 而後交換A[i]和A[j]。由於進行了交換,因此有A[i] <=x,所以知足[p,i]的數都小於等於x。而且A[j-1] > x由於根據循環不變式,被交換進A[j-1]的項目是大於x的。
  3. 終止: 當終止時, j=r-1。在partition過沖中的而最後兩行,將主元與最左的,大於x的元素進行交換,就將它移動到數組中間的位置上。所以partition的輸出知足分解步驟所作的規定要求。

快排性能最差時是Θ(n2)spa

平均性能Θ(nlgn)code

 

快排的隨機化版本blog

int  randomized-partition(int*  A, int p, int r) {
    int i = random(p,r);
    int tmp = A[r-1]; A[r-1] = A[i]; A[i] = tmp;
   return partition(A, p, r);
}

 新的快速排序過程再也不調用partition,而是調用randomized-partition排序

void quicksort(int* A, int p, int r){
  if (p < r) {
    int q = randomized-partition(A, p, r);
    quicksort(A, p, q);
    quicksort(A, q+1, r);
  }
}

擴展:

快排除了算法導論的版本外,c語言的庫函數stdlib.h也提供了一個qsort函數。它的源代碼能夠從這裏下載http://www.gnu.org/software/libc/

代碼路徑在glibc-2.27/stdlib/qsort.c. 再也不累述。

相關文章
相關標籤/搜索