1、快速排序基本思想 快速排序時C.R.A.Hoare在1962年提出的一種劃分交換排序。採用
分治策略(Divide-and-ConquerMethod) 該方法的基本思想是: (1)先從數列中取出一個數作為基準數 (2)分區過程,將比這個數大的數全放到它的右邊,小於或等於它的數全放到它的左邊,獲得一個index位置,將數組劃分為左右兩部分 (挖坑填數+分治法) (3)再對左右區間重複第二步,直到各區間只有一個數。(遞迴實現) 較難理解的地方在於第二步的區間劃分,在此採用
挖坑填數的方法。 舉例分析:
int[] arr = {3,7,5,1,6,2,4};
| 0 |
1 |
2 |
3 |
4 |
5 |
6 |
| 3 |
7 |
5 |
1 |
6 |
2 |
4 |
(1)取第一個數作為基準數。初始化為low = 0;high = 6;priv = arr[low] = 3; 解釋:由於已經將arr[0]中 的資料儲存到priv中,可以看作是在數組索引為0的位置挖坑了 (2)從high開始向左找到第一個比priv小或等於priv的數。當high=5時,小於priv,將arr[5]挖出賦值給arr[low],即arr[low]=arr[high] = 2,此時索引5的位置是坑,需要找元素來進行填充 (3)從low開始向右找到第一個比priv大或等於priv的數。當low=1時,arr[low] = 7>priv,符合條件則挖出arr[1]賦值給arr[high],即arr[high] = arr[low] = 7;此時索引low=1的位置是坑。 此時數組變成了
| 0 |
1 |
2 |
3 |
4 |
5 |
6 |
| 2 |
3 |
5 |
1 |
6 |
7 |
4 |
low = 1,high = 5 priv = 3 後面再重複上面的步驟:先從後往前找第一個小於等於基準元素的,再從前向後找第一個大於等於基準元素的。 從high開始向前找,當high=3,符合條件,將arr[3]挖出,填到上一個坑,即arr[low] =arr[1] = arr[high] = 1,此時arr[3]處為坑 從low開始向後找,當low = 2,符合條件,將arr[2]挖出,填到上一個坑即arr[3] = arr[2] = 5 此時high=3.low=2.再開始找會發現low==high,所以退出。 最後將最後一個坑arr[2]填充,用基準元素。arr[2] = priv = 3; 所得數組為:
| 0 |
1 |
2 |
3 |
4 |
5 |
6 |
| 2 |
1 |
3 |
5 |
6 |
7 |
4 |
第一輪用arr[low]將整個數組分為兩部分,以arr[2]分界,左邊的數字都小於arr[2],右邊數字都大於arr[2]。下一步即是對左右兩個區間重複上述步驟。遞迴操作。
2、快速排序實現 挖坑填數法具體實現: (1)low數組左邊界,high數組右邊界,priv = arr[low]將基準數挖出形成一個坑arr[low] (2)high由後向前找到第一個比它小的,找到後挖出此數填到前一個坑arr[low]中 (3)low由前向後找到第一個比它大的,找到後挖出此數,填到前一個坑arr[high]中 (4)再重複執行(2)、(3)步,知道low==high,將基準數priv填入到arr[low]中,返回low,low即為左右兩部分的分界處。
java代碼實現:
public int partition(int[] arr,int low,int high)是挖坑填數的具體實現,返回分界點的位置
public void qSort(int[] arr,int low,int high)是分治方法的具體實現,採用遞迴
public class quickSort {/** * @param arr 待排序數組 * @param low 剛開始表示排序範圍的第一個元素。逐漸向右移動,找到第一個比樞紐值val大的 * @param high 剛開始表示排序範圍的最後一個元素。逐漸向左移動,找到第一個比樞紐值val小的 * @return 返回分割點值所在的位置 */public int partition(int[] arr,int low,int high){int val = arr[low];//設定樞紐元素為每個序列的第一個元素while(low<high){ //要迴圈比較while(low<high&&arr[high]>=val){high--;}arr[low] = arr[high];while(low<high&&arr[low]<=val){low++;}arr[high] = arr[low];}//low = high,返回樞紐的位置arr[low] = val;return low;}public void qSort(int[] arr,int low,int high){//遞迴調用int pos;if(low<high){pos= partition(arr,low, high);qSort(arr, low, pos-1);qSort(arr, pos+1, high);}}public static void main(String[] args){int[] arr = {3,7,5,1,6,2,4};new quickSort().qSort(arr,0,arr.length-1);for(int i = 0;i<arr.length;i++){System.out.print(arr[i]+" ");}} /** *快速排序 被認為在所有同數量級(平均複雜度為O(n*logn))的排序方法中,平均效能最好。 *選取樞紐元素:但是若初始記錄已經基本有序,這樣每次如果還選擇第一個元素作為樞軸元素,則再通過樞軸劃分子序列時,便會出現“一邊倒”的情況, * 此時快速排序就完全成了冒泡排序,這便是最壞的情況,時間複雜度為O(n*n)。 * 所以通常樞軸元素的選擇一般基於“三者取中”的原則,即比較首元素、末元素、中間元素的值,取三者中中間大小的那個。 *快速排序的空間複雜度為O(logn)。 */}
3、快速排序特性 時間複雜度 O(n*logn),空間複雜度:O(logn) ,穩定性:不穩定
快速排序 被認為在所有同數量級(平均複雜度為O(n*logn))的排序方法中,平均效能最好。
選取樞紐元素:但是若初始記錄已經基本有序,這樣每次如果還選擇第一個元素作為樞軸元素,則再通過樞軸劃分子序列時,便會出現“一邊倒”的情況,此時快速排序就完全成了冒泡排序,這便是最壞的情況,時間複雜度為O(n*n)。所以通常樞軸元素的選擇一般基於“三者取中”的原則,即比較首元素、末元素、中間元素的值,取三者中中間大小的那個。