排序算法(七)
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; } }