原理
對於一組給定的記錄,通過一趟排序後,將原序列分爲兩部分,其中一部分的所有記錄均比後一部分的所有記錄小,然後再依次對前後兩部分的記錄進行快速排序,遞歸該過程,直到序列中的所有記錄均有序爲止。
程序
1 public class quicksort { 2 3 public static void quickSort(int array[],int low,int high){ 4 int pivot; 5 if(low<high){ 6 pivot = partition(array,low,high); 7 quickSort(array,low,pivot-1); 8 quickSort(array,pivot+1,high); 9 } 10 } 11 12 13 public static int partition(int array[],int low,int high){ 14 int index = array[low]; 15 while(low<high){ 16 while(low<high&&array[high]>=index) 17 high--; 18 array[low] = array[high]; 19 while(low<high&&array[low]<index) 20 low++; 21 array[high] = array[low]; 22 } 23 array[low] = index; 24 return low; 25 } 26 27 28 public static void main(String[] args){ 29 int a[] = {5,4,9,8,7,6,0,1,3,2}; 30 int len = a.length; 31 quickSort(a,0,len-1); 32 for(int i=0;i<len;i++){ 33 System.out.println(a[i]+" "); 34 } 35 } 36 37 }
優化
1.優化選取樞軸
採取三數取中法。取三個關鍵字先進性排序,將中間數作爲樞軸,一般是取左端、右端和中間三個數,也可以隨機選取。這樣至少這個中間數一定不會是最小或最大的數,從概率來說,取三個數均爲最小或最大數的可能性微乎其微,因此中間數位於較爲中間的值的肯能行就大大提高了。
將上面程序中的第14行改爲如下程序
1 int index; 2 int m = low + (high - low) / 2; //中間元素下標 3 if(array[low]>array[high]) 4 swap(array,low,high); //交換左端與右端數據,保證左端較小。 5 if(array[m]>array[high]) 6 swap(array,m,high); //交換中間與右端數據,保證中間較小。 7 if(array[m]>array[low]) 8 swap(array,low,m); //交換中間與左端數據,保證左端較小。 9 /*此時array[low]已經是整個序列左中右三個關鍵字中的中間值。*/ 10 index = array[low];
2.優化小數組時的排序方案
當數組非常小時,快速排序反而不如直接插入排序來得更好。我們可以設置一個數組長度閾值(有資料認爲7比較合適,也有認爲50更合適,實際應用可適當調整),當數組長度在設定閾值之下時,就用直接插入排序,否則用快速排序。
3.優化遞歸操作
我們知道遞歸對性能是有一定的影響的,quickSort方法在其尾部有兩次遞歸操作,如果待排序的序列劃分極不平衡,遞歸深度將趨於n,這就不僅僅是速度快慢的問題了。棧的大小是很有限的,每次遞歸都會耗費一定的棧空間,函數的參數越多,每次遞歸耗費的空間也越多。如果能減少遞歸,將會大大提高性能。
我們採取尾遞歸優化。
將程序中的5-9行改爲如下程序
1 while(low<high){ 2 pivot = partition(array,low,high); 3 quickSort(array,low,pivot-1); 4 low = pivot+1; 5 }
常見排序算法的特點和比較
排序法 | 平均時間 | 最好情形 | 最差情形 | 穩定度 | 額外空間 | 備註 |
冒泡 | O(n2) | O(n) | O(n2) | 穩定 | O(1) | n小時較好 |
選擇 | O(n2) | O(n2) | O(n2) | 不穩定 | O(1) | n小時較好 |
插入 | O(n2) | O(n) | O(n2) | 穩定 | O(1) | 大部分已排序時較好 |
Shell | O(nlogn) | O(n1.3) | O(ns) 1<s<2 | 不穩定 | O(1) | s是所選分組 |
堆 | O(nlogn) | O(nlogn) | O(nlogn) | 不穩定 | O(1) | n大時較好 |
歸併 | O(nlogn) | O(nlogn) | O(nlogn) | 穩定 | O(n) | n大時較好 |
快速 | O(nlogn) | O(nlogn) | O(n2) | 不穩定 | O(nlogn) | n大時較好 |