快速排序(Quick Sort)
快速排序是由東尼·霍爾所發展的一種排序算法。在平均狀況下,排序n個元素要O(nlogn)次比較。在最壞狀況下則需要O(n^2)次比較,但這種狀況並不常見。事實上,快速排序通常明顯比其他O(nlogn)算法更快,因為它的內部循環可以在大部分的架構上很有效率地被實現出來。
快速排序使用分治策略(Divide and Conquer)來把一個序列分為兩個子序列。步驟為:
- 從序列中挑出一個元素,作為"基准"(pivot).一般使用第一個元素或最后一個元素作為比較的基准。
- 把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的數可以到任一邊),這個稱為分區(partition)操作。
- 對每個分區遞歸地進行步驟1~2.
Python代碼:
def Partition(seq,left,right): key=seq[right] tail=left-1 for i in range(left,right): if seq[i]<=key: tail+=1 if tail!=i: seq[tail],seq[i]=seq[i],seq[tail] seq[tail+1],seq[right]=seq[right],seq[tail+1] return tail+1 def QuickSort(seq,left,right): if left>=right: return index=Partition(seq,left,right) QuickSort(seq,left,index-1) QuickSort(seq,index+1,right) return seq s = [6, 8, 1, 4, 3, 9, 5, 4, 11, 2, 2, 15, 6] print("before sort:",s) s1 = QuickSort(s, left = 0, right = len(s) - 1) print("after sort:",s1)
本文將要實現快排的一種思路如下:
第一個函數Partition()的作用是:給定一個序列和序列的起始位置和末尾元素的位置,以末尾元素為基准,將小於基准的數據放在基准的左邊,大於基准的數據放在右邊,最后返回基准數據的索引下標
第二個函數QuickSort()的作用是不斷的遞歸循環,直到出現left>=right的情況結束
其中,最難理解的是Partition函數。在這里做如下解釋:
例如一組數據:s = [6, 8, 1, 4, 3, 9, 5, 4, 11, 2, 2, 15, 7],n=siezof(s)
第一步:以序列的最后一個元素作為基准,pivot=7
第二步:從左到右遍歷前n-1個元素,這里先借助一個輔助變量tail,tail的作用是作為一個索引,用來表示遍歷過程中,所有比基准小的數組成的子序列中的最后一個元素的索引。特別繞!例如遍歷s,一個元素6要比pivot=7小,所以子序列為[6],tail值為0,然后繼續向前遍歷,第二個元素8比pivot大,跳過,遍歷第三個元素1要比pivot小,那么子序列為[6,1],tail值為2,遍歷第四個元素4要比pivot小,那么子序列為[6,1,4],tail值為3,.。。。最后tail+1即為pivot=7在原序列中的位置。
C代碼:摘自:http://www.cnblogs.com/eniac12/p/5329396.html
#include <stdio.h> void Swap(int A[], int i, int j) { int temp = A[i]; A[i] = A[j]; A[j] = temp; } int Partition(int A[], int left, int right) // 划分函數 { int pivot = A[right]; // 這里每次都選擇最后一個元素作為基准 int tail = left - 1; // tail為小於基准的子數組最后一個元素的索引 for (int i = left; i < right; i++) // 遍歷基准以外的其他元素 { if (A[i] <= pivot) // 把小於等於基准的元素放到前一個子數組末尾 { Swap(A, ++tail, i); } } Swap(A, tail + 1, right); // 最后把基准放到前一個子數組的后邊,剩下的子數組既是大於基准的子數組 // 該操作很有可能把后面元素的穩定性打亂,所以快速排序是不穩定的排序算法 return tail + 1; // 返回基准的索引 } void QuickSort(int A[], int left, int right) { if (left >= right) return; int pivot_index = Partition(A, left, right); // 基准的索引 QuickSort(A, left, pivot_index - 1); QuickSort(A, pivot_index + 1, right); } int main() { int A[] = { 5, 2, 9, 4, 7, 6, 1, 3, 8 }; // 從小到大快速排序 int n = sizeof(A) / sizeof(int); QuickSort(A, 0, n - 1); printf("快速排序結果:"); for (int i = 0; i < n; i++) { printf("%d ", A[i]); } printf("\n"); return 0; }