2. 交換排序—快速排序(Quick Sort)
基本思想:
1、選擇一個基準元素,通常選擇第一個元素或者最後一個元素。
2、通過一趟排序將待排序的記錄分割成獨立的倆部分,其中一部分記錄元素值均比基準元素值小,另一部分記錄元素的值均大於基準元素值。
3、此時基準元素在其排好序後的正確位置。
4、然後分別對這倆部分記錄繼續用同樣的方法進行排序,知道整個序列有序。
快速排序的示例:
(a)一趟排序的過程:
(b)排序的全過程:
演算法的實現:
遞迴實現:
public class QuickSort { public static void main(String[] args) { int[] a = { 12, 23, 34, 45, 54, 43, 32, 21 }; quickSort(a, 0, a.length - 1); for (int i = 0; i < a.length; i++) { System.out.print(a[i] + " "); } } public static void quickSort(int[] a, int low, int high) { if (low < high) { int privotLoc = partition(a, low, high);// 將表一分為二 quickSort(a, low, privotLoc - 1);// 遞迴對低子表遞迴排序 quickSort(a, privotLoc + 1, high);// 遞迴對高子表遞迴排序 } } public static int partition(int[] a, int low, int high) { int privotkey = a[low]; // 基準元素 while (low < high) { // 從表的倆端,交替的向中間掃描 while (low < high && a[high] >= privotkey) { // 從high // 所指位置向前搜尋,至多到low+1 // 位置。將比基準元素小的交換到低端 --high; } swap(a, low, high); while (low < high && a[low] <= privotkey) { ++low; } swap(a, low, high); } return low; } public static void swap(int a[], int low, int high) { int temp = a[low]; a[low] = a[high]; a[high] = temp; } }
分析:
快速排序是被認為是同數量級(O(nlon2n))的排序方法中平均效能最好的。但若初始序列按關鍵碼有序或基本有序時,快速排序反而退化為氣泡排序。為改進之,通常以“三者取中法”來選取基準記錄,即將排序區間的倆個端點與中點三個記錄關鍵碼居中的調整為支點記錄。快速排序就是一個不穩定的排序方法。
快速排序的改進:
在本改進方法中,只對長度大於k的子序列遞迴呼叫快速排序,,讓原序列基本有序,然後對整個基本有序的序列用插入排序演算法排序。實踐證明,改進後的時間複雜度有所減低,且當k取值為8左右時,改進演算法的效能最佳。演算法思想如下:
public class QuickSort2 { public static void main(String[] args) { int[] a = { 12, 23, 34, 45, 54, 43, 32, 21 ,23,65,89,32,19,2,3,921,980}; quickSort(a, 0, a.length - 1,4); for (int i = 0; i < a.length; i++) { System.out.print(a[i] + " "); } } public static void quickSort(int[] a, int low, int high, int k){ quickSortImporve(a, low, high, k); for(int i=1;i<a.length;i++){ int x = a[i]; int j = i-1; while(j>=0 && x<a[j]){ a[j+1] = a[j]; j--; } a[j+1] = x; } } public static void quickSortImporve(int[] a,int low,int high,int k){ if(high-low>k){ //長度大於k時遞迴,k為指定的數 int pivotLoc = partition(a, low, high); quickSortImporve(a, low, pivotLoc-1, k); quickSortImporve(a, pivotLoc+1, high, k); } } public static int partition(int[] a, int low, int high){ int privotKey = a[low]; //基準元素 while(low<high){ //從表的倆端,交替的向中間掃描 while(low < high && a[high] >= privotKey) { --high; } swap(a,low,high); while(low < high && a[low] <= privotKey){ ++low; } swap(a,low,high); } return low; } public static void swap(int[] a, int low,int high){ int temp = a[low]; a[low] = a[high]; a[high] = temp; } }