大二其實已經學習過了快排,可是如今基本上已經忘記了快排的細節和具體實現。如今爲了準備可能的面試,從新複習一下快速排序。溫故知新,古人誠不欺我。主要以《算法導論》爲教材。面試
《算法導論》這本書在介紹算法時,首先給出算法的描述,也就是僞碼,而後就是算法的正確性證實和優化。本文首先也是給出算法的僞碼,至於正確性的證實,仍是看本身可否勝任。算法
QUICKSORT(A,p,r) if p < r then q = PARTITION(A,p,r) QUICKSORT(A,p,q-1) QUICKSORT(A,q+1,r)
瞭解快排,就會知道快排的核心思想就是每次實現這樣一個數組:選定數組中某一個值,確保該值左邊的元素都比它小,右邊的元素都比它大。這樣雖然不能保證改值左邊和右邊的元素必定是有序的,可是必定可以保證該值在排序後的數組中的相對位置不會改變。好比說A[i]此時在第i個位置,當整個數組排完序以後,A[i]必定仍是在i。這樣也就知道爲何上面代碼中遞歸的時候不用包含q的值,由於它的位置已經肯定了。數組
通過以上的分析,就不難在實際編碼中寫出快排的大體框架了。框架
顯而易見,快排採用的是分治的思想。每次將一個任務分爲兩個或者多個部分來解決。可是如何劃分其實才是快排的難點和重點。在面試的工程中被問道了這個問題,本身徹底忘了如何劃分。學習
若是要保證每次排序後的數組都知足左邊的都比指定元素要小,右邊則都要大,必需要選擇一個參照值做爲比較的對象,這個參考值就叫作主元。肯定了組員,就開始遍歷比較。優化
假設每次選取的都是最右邊的元素做爲主元,那麼就能夠從左到右來比較和肯定元素的位置。具體見下面的僞碼。ui
PARTITION(A,p,r) x = A[r] i = p - 1 for j : p to r do if A[j] < x then i = i + 1 exchange(A[i],A[j]) exchange(A[i+1],A[r]) return i+1
大體的策略就是儘可能讓比主元小的元素排在前面。就這樣,很神奇的整個數組就排完序了。編碼
/************************************************************************* > File Name: myfiles/C/sort/quicksort.c > Author: ma6174 > Mail: ma6174@163.com > Created Time: 2014年10月06日 星期一 11時38分28秒 ************************************************************************/ #include<stdio.h> #define maxn 100 int A[maxn]; int n; /* 輸入數據 */ void read() { printf("input the num:\n"); scanf("%d",&n); int i; for(i = 0; i < n; i++) { scanf("%d",&A[i]); } } /* 分治 */ int partition(int A[], int p, int r) { int key = A[r]; int i = p - 1; int j; for(j = p; j < r; j++) { if(A[j] < key) { /* 目前爲止,沒有等於好也能夠正確執行,可是我不肯定要不要等號*/ i++; int temp = A[i]; A[i] = A[j]; A[j] = temp; } } int temp = A[i+1]; A[i+1] = key; A[r] = temp; return i+1; } /* 快排 */ void quick_sort(int A[], int p, int r) { if(p < r) { int q = partition(A,p,r); quick_sort(A,p,q-1); quick_sort(A,q+1,r); } } /* 輸出 */ void write() { printf("the sorted array:\n"); int i; for(i = 0; i < n; i++) { printf("%d ",A[i]); } printf("\n"); } int main() { read(); quick_sort(A,0,n-1); write(); }
若是本身在草稿紙上寫寫整個快排的步驟,不難發現對於逆序的序列,上面的快排版本的複雜度是O(n2),因此有優化。很簡單,每次隨機的選取一個元素做爲主元。對象
-end-blog