白話經典演算法快速排序-快速搞定
快速排序演算法和歸併排序,都是由於時間複雜度只有O(N*logN),得到大量使用。快速排序的核心思想就是分而治之,我每次處理只負責將一個元素的位置排序正確,其他就先不管。那分而治之,遞迴處理後,所有元素都回到有序的正確位置,排序就完成了。
演算法的時間複雜度,N就是因為,需要給每個元素都進行一次調整排序。而logN的時間複雜度,就是給元素調整排序,需要進行拆半資料遞迴。
演算法的基本思想是:
1.先從數列中取出一個數作為基準數。需要進行N次。
2.基於基準數進行分割槽,分割槽後,基準數處於正確排序的位置,其他數字繼續亂序。處理過程就是將比這個數大的數全放到它的右邊,小於或等於它的數全放到它的左邊。
3.再對左右區間重複第二步,直到各區間只有一個數。
直接看程式碼和註釋,後文有詳細介紹:
public int adJustArray(int[] arr, int left, int right) { int i = left; int j = right; int base = arr[i];//挖坑,將這個數先取出,待會移動i,j指標去填坑 while (i < j) {//開始一次次遍歷,找到合適的數去填坑、以及挖坑 //開始做最right邊找一個比坑小或者等於的數填進來 while (i < j && arr[j] >= base) {//記住,這裡是用base,而不是arr[i] j--;//如果➡右指標的數比坑裡的數大,那就不交換,直接繼續移動尋找 } //找到了一個arr[j]比坑小,或者說i等於j啦,跳出了while迴圈 if (i < j) {//判斷一下,是i小於j,才賦值填坑 arr[i] = arr[j];//這樣,j這邊就有一個坑,需要左指標移動,找一個比坑的數大的填進來 i++; } //開始做最left邊移動,找一個比坑大的數填進去 while (i < j && arr[i] < base) {//記住,這裡是用base, i++; } if (i < j) { arr[j] = arr[i];//將i填入j後,i這裡就是一個新的坑 j--;//需要移動j來填 } } //while 迴圈結束時候,i==j //基準base就放入i位置這個坑,固定下來 arr[i] = base; return i; } //分治法 public void quickSort(int[] arr, int left, int right) { if (left < right) { int newBase = adJustArray(arr, left, right);//執行一次挖坑調整排序,將newbase這個元素固定下來。 //接下來,遞迴左邊的、右邊的數 quickSort(arr, left, newBase - 1); quickSort(arr, newBase + 1, right); } } public static void main(String[] args) { int[] a = new int[]{6,23,57,2,8,6,9}; QuickSort quickSort= new QuickSort(); quickSort.quickSort(a,0,a.length-1); for (int i: a) { System.out.println(i); } }
借鑑挖坑填數+分治法:
以一個數組作為示例,取區間第一個數為基準數。
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
72 |
6 |
57 |
88 |
60 |
42 |
83 |
73 |
48 |
85 |
初始時,i = 0; j = 9; X = a[i] = 72
由於已經將a[0]中的數儲存到X中,可以理解成在陣列a[0]上挖了個坑,可以將其它資料填充到這來。
從j開始向前找一個比X小或等於X的數。當j=8,符合條件,將a[8]挖出再填到上一個坑a[0]中。a[0]=a[8]; i++; 這樣一個坑a[0]就被搞定了,但又形成了一個新坑a[8],這怎麼辦了?簡單,再找數字來填a[8]這個坑。這次從i開始向後找一個大於X的數,當i=3,符合條件,將a[3]挖出再填到上一個坑中a[8]=a[3]; j--;
陣列變為:
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
48 |
6 |
57 |
88 |
60 |
42 |
83 |
73 |
88 |
85 |
i = 3; j = 7; X=72
再重複上面的步驟,先從後向前找,再從前向後找。
從j開始向前找,當j=5,符合條件,將a[5]挖出填到上一個坑中,a[3] = a[5]; i++;
從i開始向後找,當i=5時,由於i==j退出。
此時,i = j = 5,而a[5]剛好又是上次挖的坑,因此將X填入a[5]。
陣列變為:
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
48 |
6 |
57 |
42 |
60 |
72 |
83 |
73 |
88 |
85 |
可以看出a[5]前面的數字都小於它,a[5]後面的數字都大於它。因此再對a[0…4]和a[6…9]這二個子區間重複上述步驟就可以了。
對挖坑填數進行總結
1.i =L; j = R; 將基準數挖出形成第一個坑a[i]。
2.j--由後向前找比它小的數,找到後挖出此數填前一個坑a[i]中。
3.i++由前向後找比它大的數,找到後也挖出此數填到前一個坑a[j]中。
4.再重複執行2,3二步,直到i==j,將基準數填入a[i]中。
照著這個總結很容易實現挖坑填數的程式碼。