1. 程式人生 > 其它 >快速排序和希爾排序

快速排序和希爾排序


title: "快速排序和希爾排序"
author: Sun-Wind
date: January 2, 2021

背景:複習使用

快速排序

思想和時間複雜度

快速排序是由東尼·霍爾所發展的一種排序演算法。
在平均狀況下,排序 n 個專案要 Ο(nlogn) 次比較。在最壞狀況下則需要 Ο(n2) 次比較,但這種狀況並不常見。
快速排序又是一種分而治之思想在排序演算法上的典型應用。
雖然 Worst Case 的時間複雜度達到了 O(n²),但是在大多數情況下都比平均時間複雜度為 O(n logn) 的排序演算法表現要更好。

快速排序的最壞執行情況是 O(n²),比如說順序數列的快排。但它的平攤期望時間是 O(nlogn),且 O(nlogn) 記號中隱含的常數因子很小,比複雜度穩定等於 O(nlogn) 的歸併排序要小很多。所以,對絕大多數順序性較弱的隨機數列而言,快速排序總是優於歸併排序。 ------《演算法藝術和資訊學奧賽》

由於基準值的不確定,快速排序經常要交換兩個數的相對位置,所以快速排序不是穩定的排序演算法
可以說,快速排序是優化版的氣泡排序

演算法步驟

  • 從數列中挑出一個元素,稱為 "基準"(pivot);
  • 重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分割槽退出之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作;
  • 遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序;

程式碼實現

Paritition1(int A[], int low, int high) {
   int pivot = A[low];//基準初始值從low開始
   while (low < high) {
     while (low < high && A[high] >= pivot) {
       --high;
     }
     A[low] = A[high];//找到high起第一個比基準值小的元素
     while (low < high && A[low] <= pivot) {
       ++low;
     }
     A[high] = A[low];//找到low起第一個比基準值大的元素
   }
   A[low] = pivot;//還原基準值
   //由於是遞迴實現,此時已經按照基準值分好了界限
   return low;
 }

 void QuickSort(int A[], int low, int high) //快排母函式
 {
   if (low < high) {
     int pivot = Paritition1(A, low, high);
     QuickSort(A, low, pivot - 1);
     QuickSort(A, pivot + 1, high);
   }
 }

希爾排序

思想和時間複雜度

希爾排序是希爾(Donald Shell)於1959年提出的一種排序演算法。
希爾排序也是一種插入排序,它是簡單插入排序經過改進之後的一個更高效的版本,也稱為縮小增量排序,同時該演算法是衝破O(n2)的第一批演算法之一。
希爾排序的基本思想是:先將整個待排序的記錄序列分割成為若干子序列分別進行直接插入排序,待整個序列中的記錄"基本有序"時,再對全體記錄進行依次直接插入排序。
希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個檔案恰被分成一組,演算法便終止。

演算法步驟

  • 選擇一個增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
  • 按增量序列個數 k,對序列進行 k 趟排序;
  • 每趟排序,根據對應的增量 ti,將待排序列分割成若干長度為 m 的子序列,分別對各子表進行直接插入排序。僅增量因子為 1 時,整個序列作為一個表來處理,表長度即為整個序列的長度。

程式碼實現

void shellsort(int arr[], int n) {
    int gap, i, j, temp;

    for(gap = n/2; gap > 0; gap /= 2)
        for(i = gap; i < n; i++)
            for(j = i - gap; j >= 0 && arr[j] > arr[j+gap]; j -= gap) {
                temp = arr[j];
                arr[j] = arr[j+gap];
                arr[j+gap] = temp;
            }
}