標籤:排序演算法 快速排序
參考書籍:《資料結構與演算法分析——C語言描述》
快速排序是在實踐中最快的已知排序演算法,它的平均時間複雜度O(NlogN)。當然在最壞的情況下為O(N^2),但稍加努力就可以避免這種情形。
像歸併排序一樣,快速排序也是一種分治的遞迴演算法,可簡單表示如下:
將數組S排序的基本演算法由下列簡單的四步組成。
1、數組元素至少大於或等於4個,否則直接利用插入排序完成。
2、利用特定方法(三數中值分割法)取數組某一特定元素V,稱之為樞紐元。
3、將數組中其他元素(即S-{V})分成兩個不相交的子集。S1={x∈S-{V} | x≤V}和S2={x∈S-{V} | x≥V}。
4、繼而對兩個子集S1和S2進行同理1-3的遞迴運算。
如何選取樞紐元呢?
此處我們介紹是三數中值分割法。選取數組中最左端、最右端和中心位置的三個元素,比較三個元素的大小,並按照小的在左邊交換彼此位置,取中間值作為樞紐元。
例如:
對於初始序列:
left=8;right=0;center=6。
顯然此處樞紐元應為piovt=6;並且此時的排序為:
然後我們選取兩個指標i和j。從序列的首尾兩端出發,除樞紐元外的元素與樞紐元進行比較。此時可把樞紐元6移至right-1的位置(因為right已經比piovt大了,left已經比piovt小了)。
即:
如果i指示的數比樞紐元小,則i++;直至遇到大於等於樞紐元的數停止。
如果j指示的數比樞紐元大,則j++;直至遇到小於等於樞紐元的數停止。
若此時i<j(說明元素沒有全部比完),則交換i和j位置的數。繼續上述的比較,直至i≥j(說明元素全部比完)。
比完時序列如下:
此時在交換位置i的數和樞紐元。如所示:
樞紐元已將原序列分割為兩個子集:
1、大於樞紐元:7,9,8
2、小於樞紐元:0,1,4,2,3,5
同理可以將兩個子集繼續進行如此的分割排序。
代碼實現:
#include<stdio.h>void QuickSort(int *data,int n);void Qsort(int *data,int left,int right);int Median3(int *data,int left,int right);//3數中值分割法取出樞紐元void Swap(int *a,int *b);void InsertSort(int *data,int N);int main(){ int i=0; int data[8]={34,8,64,51,32,21,9,5}; printf("Before Sort:\n"); for(i=0;i<8;i++) { printf("%d\t",data[i]); } QuickSort(data,8); printf("\nAfter Sort:\n"); for(i=0;i<8;i++) { printf("%d\t",data[i]); } return 0;}void Swap(int *a,int *b){ int tmp; tmp=*a; *a=*b; *b=tmp;}int Median3(int *data,int left,int right){ int center=(left+right)/2; //確保data[left]<=data[center]<=data[right] if(data[left]>data[right]) Swap(&data[left],&data[right]); if(data[left]>data[center]) Swap(&data[left],&data[center]); if(data[center]>data[right]) Swap(&data[center],&data[right]); Swap(&data[center],&data[right-1]); return data[right-1];}void QuickSort(int *data,int n){ Qsort(data,0,n-1);}void Qsort(int *data,int left,int right){ int i,j; int pivot; if(left+3<=right)//保證至少有4個數 { pivot=Median3(data,left,right); i=left; j=right-1; for(;;) { while(data[++i]<pivot); while(data[--j]>pivot); if(i<j) Swap(&data[i],&data[j]); else break; } Swap(&data[i],&data[right-1]); Qsort(data,left,i-1); Qsort(data,i+1,right); } else InsertSort(data+left,right-left+1);//調用插入排序}void InsertSort(int *data,int N){ int i=0,j=0; int tmp=0; for(i=1;i<N;i++) { tmp=data[i];//待插入的值 for(j=i;j>0 && data[j-1]>tmp;j--)//在已排序數組中從後往前遍曆,直到找到插入的位置j data[j]=data[j-1]; data[j]=tmp; }}
排序演算法——快速排序