快速排序
算法思想:基於分治的思想,是冒泡排序的改進型。首先在數組中選擇一個基准點(該基准點的選取可能影響快速排序的效率,后面講解選取的方法),然后分別從數組的兩端掃描數組,設兩個指示標志(lo指向起始位置,hi指向末尾),首先從后半部分開始,如果發現有元素比該基准點的值小,就交換lo和hi位置的值,然后從前半部分開始掃秒,發現有元素大於基准點的值,就交換lo和hi位置的值,如此往復循環,直到lo>=hi,然后把基准點的值放到hi這個位置。一次排序就完成了。以后采用遞歸的方式分別對前半部分和后半部分排序,當前半部分和后半部分均有序時該數組就自然有序了。
排序過程:
算法實現:
public static int partition(int []array,int lo,int hi){ //固定的切分方式 int key=array[lo]; while(lo<hi){ while(array[hi]>=key&&hi>lo){//從后半部分向前掃描 hi--; } array[lo]=array[hi]; while(array[lo]<=key&&hi>lo){從前半部分向后掃描 lo++; } array[hi]=array[lo]; } array[hi]=key; return hi; } public static void sort(int[] array,int lo ,int hi){ if(lo>=hi){ return ; } int index=partition(array,lo,hi); sort(array,lo,index-1); sort(array,index+1,hi); }
快速排序的時間復雜度為O(NlogN).
快速排序的優化
對於基准位置的選取一般有三種方法:固定切分,隨機切分和三取樣切分。固定切分的效率並不是太好,隨機切分是常用的一種切分,效率比較高,最壞情況下時間復雜度有可能為O(N2).對於三數取中選擇基准點是最理想的一種。
三數取中切分:
public static int partition(int []array,int lo,int hi){ //三數取中 int mid=lo+(hi-lo)/2; if(array[mid]>array[hi]){ swap(array, mid, hi); } if(array[lo]>array[hi]){ swap(array, lo, hi); } if(array[mid]>array[lo]){ swap(array, mid, lo); } int key=array[lo]; while(lo<hi){ while(array[hi]>=key&&hi>lo){ hi--; } array[lo]=array[hi]; while(array[lo]<=key&&hi>lo){ lo++; } array[hi]=array[lo]; } array[hi]=key; return hi; }
private void swap(int[] arr, int i, int j) {
if (i == j) {
return;
}
int n = arr[i];
arr[i] = arr[j];
arr[j] = n;
}
public static void sort(int[] array,int lo ,int hi){ if(lo>=hi){ return ; } int index=partition(array,lo,hi); sort(array,lo,index-1); sort(array,index+1,hi); }
快速排序在序列中元素很少時,效率將比較低,不然插入排序,因此一般在序列中元素很少時使用插入排序,這樣可以提高整體效率。
public static void quick(int []array ,int lo,int hi){ if(hi-lo+1<10){ insertSort(array); }else{ quickSort(array,lo,hi); } }