【筆記】快速排序

Time-space發表於2017-11-05

  快速排序是對氣泡排序的一種改進。

  基本演算法思想:通過一趟排序將待排記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。

  假設待排序的序列為{L.r[s],L.r[s+1],,L.r[t]}

\{L.r[s],L.r[s+1],…,L.r[t]\}
,首先任意選取一個一個記錄(通常可選第一個記錄L.r[s]
L.r[s]
)作為樞軸(pivot),然後按下述原則重新排列其餘記錄:將所有關鍵字較它喜愛哦的記錄都安置在它的位置之前,將所有的關鍵字較它大的記錄都安置在它的位置之後。由此可以該樞軸記錄最後所落的位置i作為分界線,將序列{L.r[s],L.r[s+1],,L.r[t]}
\{L.r[s],L.r[s+1],…,L.r[t]\}
分割成兩個子序列{L.r[s],L.r[s+1],,L.r[i1]}
\{L.r[s],L.r[s+1],…,L.r[i-1]\}
{L.r[i+1],L.r[i+2],,L.r[t]}
\{L.r[i+1],L.r[i+2],…,L.r[t]\}
。這個過程稱作一趟快速排序(或一次劃分)。
  一趟快速排序的具體做法是:附設兩個指標low和high,它們的初值分別為low和high,設樞軸記錄的關鍵字為pivotkey,則首先從high所指的位置起向前搜尋找到第一個關鍵字小於pivotkey的記錄和樞軸記錄相互交換,然後從low所指的位置起向後搜尋,找到第一個關鍵字大於pivotkey的記錄和樞軸記錄相互交換,重複這兩步直至low=high為止。

  若待排序列中止嘔一個記錄,顯然已經有序,否則進行一趟快速排序後再分別對分割所得的兩個子序列進行快速排序,如下圖所示。


這裡寫圖片描述

  • 型別定義
 #define MAXSIZE 20 /* 一個用作示例的小順序表的最大長度 */
 typedef int InfoType; /* 定義其它資料項的型別 */
 typedef int KeyType; /* 定義關鍵字型別為整型 */
 typedef struct
 {
   KeyType key; /* 關鍵字項 */
   InfoType otherinfo; /* 其它資料項,具體型別在主程中定義 */
 }RedType; /* 記錄型別 */

 typedef struct
 {
   RedType r[MAXSIZE+1]; /* r[0]閒置或用作哨兵單元 */
   int length; /* 順序表長度 */
 }SqList; /* 順序表型別 */
  • 快速排序函式
void QuickSort(SqList *L)
 { /* 對順序表L作快速排序。 */
   QSort(L,1,(*L).length);
 }

 void QSort(SqList *L,int low,int high)
 { /* 對順序表L中的子序列L.r[low..high]作快速排序。演算法10.7 */
   int pivotloc;
   if(low<high)
   { /* 長度大於1 */
     pivotloc=Partition(L,low,high); /* 將L.r[low..high]一分為二 */
     QSort(L,low,pivotloc-1); /* 對低子表遞迴排序,pivotloc是樞軸位置 */
     QSort(L,pivotloc+1,high); /* 對高子表遞迴排序 */
   }
 }
 int Partition(SqList *L,int low,int high)
 { /* 交換順序表L中子表L.r[low..high]的記錄,使樞軸記錄到位, */
   /* 並返回其所在位置,此時在它之前(後)的記錄均不大(小)於它。 */
   RedType t;
   KeyType pivotkey;
   pivotkey=(*L).r[low].key; /* 用子表的第一個記錄作樞軸記錄 */
   while(low<high)
   { /* 從表的兩端交替地向中間掃描 */
     while(low<high&&(*L).r[high].key>=pivotkey)
       --high;
     t=(*L).r[low]; /* 將比樞軸記錄小的記錄交換到低端 */
     (*L).r[low]=(*L).r[high];
     (*L).r[high]=t;
     while(low<high&&(*L).r[low].key<=pivotkey)
       ++low;
     t=(*L).r[low]; /* 將比樞軸記錄大的記錄交換到高階 */
     (*L).r[low]=(*L).r[high];
     (*L).r[high]=t;
   }
   return low; /* 返回樞軸所在位置 */
 }
  • 主程式
#include<stdio.h>
#define N 8
void print(SqList L)
 {
   int i;
   for(i=1;i<=L.length;i++)
     printf("(%d,%d)",L.r[i].key,L.r[i].otherinfo);
   printf("\n");
 }

 void main()
 {
   RedType d[N]={{49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{27,7},{49,8}};
   SqList l;
   int i;
   for(i=0;i<N;i++)
     l.r[i+1]=d[i];
   l.length=N;
   printf("排序前:\n");
   print(l);
   QuickSort(&l);
   printf("排序後:\n");
   print(l);
 }
  • 測試結果


這裡寫圖片描述

相關文章