簡述
快速排序是一種排序執行效率很高的排序算法,它利用分治法來對待排序序列進行分治排序,它的思想主要是通過一趟排序將待排記錄分隔成獨立的兩部分,其中的一部分比關鍵字小,后面一部分比關鍵字大,然后再對這前后的兩部分分別采用這種方式進行排序,通過遞歸的運算最終達到整個序列有序,下面我們簡單進行闡述。
快排思路
我們從一個數組來逐步逐步說明快速排序的方法和思路。
- 假設我們對數組{7, 1, 3, 5, 13, 9, 3, 6, 11}進行快速排序。
- 首先在這個序列中找一個數作為基准數,為了方便可以取第一個數。
- 遍歷數組,將小於基准數的放置於基准數左邊,大於基准數的放置於基准數右邊。
- 此時得到類似於這種排序的數組{3, 1, 3, 5, 6, 7, 9, 13, 11}。
- 在初始狀態下7是第一個位置,現在需要把7挪到中間的某個位置k,也即k位置是兩邊數的分界點。
- 那如何做到把小於和大於基准數7的值分別放置於兩邊呢,我們采用雙指針法,從數組的兩端分別進行比對。
- 先從最右位置往左開始找直到找到一個小於基准數的值,記錄下該值的位置(記作 i)。
- 再從最左位置往右找直到找到一個大於基准數的值,記錄下該值的位置(記作 j)。
- 如果位置i<j,則交換i和j兩個位置上的值,然后繼續從(j-1)的位置往前和(i+1)的位置往后重復上面比對基准數然后交換的步驟。
- 如果執行到i==j,表示本次比對已經結束,將最后i的位置的值與基准數做交換,此時基准數就找到了臨界點的位置k,位置k兩邊的數組都比當前位置k上的基准值或都更小或都更大。
- 上一次的基准值7已經把數組分為了兩半,基准值7算是已歸位(找到排序后的位置)。
- 通過相同的排序思想,分別對7兩邊的數組進行快速排序,左邊對[left, k-1]子數組排序,右邊則是[k+1, right]子數組排序。
- 利用遞歸算法,對分治后的子數組進行排序。
快速排序之所以比較快,是因為相比冒泡排序,每次的交換都是跳躍式的,每次設置一個基准值,將小於基准值的都交換到左邊,大於基准值的都交換到右邊,這樣不會像冒泡一樣每次都只交換相鄰的兩個數,因此比較和交換的此數都變少了,速度自然更高。當然,也有可能出現最壞的情況,就是仍可能相鄰的兩個數進行交換。
快速排序基於分治思想,它的時間平均復雜度很容易計算得到為O(NlogN)。
代碼實現
1 /** 2 * 快速排序 3 * @param array 4 */ 5 public static void quickSort(int[] array) { 6 int len; 7 if(array == null 8 || (len = array.length) == 0 9 || len == 1) { 10 return ; 11 } 12 sort(array, 0, len - 1); 13 } 14 15 /** 16 * 快排核心算法,遞歸實現 17 * @param array 18 * @param left 19 * @param right 20 */ 21 public static void sort(int[] array, int left, int right) { 22 if(left > right) { 23 return; 24 } 25 // base中存放基准數 26 int base = array[left]; 27 int i = left, j = right; 28 while(i != j) { 29 // 順序很重要,先從右邊開始往左找,直到找到比base值小的數 30 while(array[j] >= base && i < j) { 31 j--; 32 } 33 34 // 再從左往右邊找,直到找到比base值大的數 35 while(array[i] <= base && i < j) { 36 i++; 37 } 38 39 // 上面的循環結束表示找到了位置或者(i>=j)了,交換兩個數在數組中的位置 40 if(i < j) { 41 int tmp = array[i]; 42 array[i] = array[j]; 43 array[j] = tmp; 44 } 45 } 46 47 // 將基准數放到中間的位置(基准數歸位) 48 array[left] = array[i]; 49 array[i] = base; 50 51 // 遞歸,繼續向基准的左右兩邊執行和上面同樣的操作 52 // i的索引處為上面已確定好的基准值的位置,無需再處理 53 sort(array, left, i - 1); 54 sort(array, i + 1, right); 55 }
參考資料
1、《啊哈!算法》/ 啊哈磊著. 人民郵電出版社