首先,用一句話介紹快速排序——選出一個基準值,用基準值將數組分爲兩邊,左邊小於基準值,右邊大於基準值,然後又將左邊和右邊進行同樣的操作,直到整個數組有序。
下面用易於理解的方式闡釋一下快速排序的大致步驟:
這裏將小的這邊稱爲(左派),大的這邊稱爲(右派)
- 選擇一個基準值(一般是第一個元素) (左派的擔保)
- 右派自右向左找一個數小於基準數,然後交給左派 (借給左派)
- 左派自左向右找一個數,交給右派 (還給右派)
- 最終可能存在的兩種狀況:
4.1 左派找到的大於基準數的個數與右派找到的小於基準數的個數相等 (左派還清債務,收回擔保)
4.2 左派找到的大於基準數的個數小於右派找到的小於基準數的個數 (左派未還清債務,交換擔保)
4.3 注意:是不存在大於這種可能的,清理清思路,是右派借,左派還,右派借,左派還…(關鍵在於左派能否還清)
上面並未提到左派如何處理右派借,以及右派如何處理左派還,這裏很好理解:
左派和右派其實是兩個數組,左派先把基準值支出去,那麼左派就有一個空,所以右派借來的就用於補左派的空,於是右派又有了一個空,於是左派就還了一個用於補右派的空。以此反覆,直到左右大小區分,再用基準值去補最後一個空。
這其實和拼圖遊戲是很像的,缺口的數量是沒有變的(只有一個),變的只是缺口的位置(左派和右派來回變動)。我們的目標也是從無序到有序。
下面舉一個栗子
下面是待排序數組
1) 選擇基準值(擔保):62 (注意缺口的數是沒有任何意義的)
2)右派從44向左找一個數小於基準值:44(填到62這個缺口)
3)左派從72向右找一個數大於基準數:72(填到44這個缺口)
1)右派從44向左找一個數小於基準值:5(填到72這個缺口)
2)左派從72向右找一個數大於基準數:89(填到5這個缺口)
1)右派從44向左找一個數小於基準值:24(填到89這個缺口)
2)左派從72向右找一個數大於基準數:67(填到24這個缺口)
找完了,這時左派找到的大於基準數的個數與右派找到的小於基準數的個數相等(將基準值填到67這個缺口)——也就是上面結果的第一種,這裏就不舉第二個例子了
然後就是將左派與右派按照同樣的步驟,
有興趣的可以用excel等軟件像我一樣打草稿弄懂過程(注意這個是草稿)
下面是代碼,網上有許多不同的代碼,主要是思想清晰,所以這裏只給出快速排序的一種實現方案
package title;
/**
* 快速排序
*/
public class QuickSoft {
public static void quickSort(int[] arr) {
if (arr != null && arr.length > 1)
quickSort(arr, 0, arr.length - 1);
}
public static void quickSort(int[] arr, int left, int right) {
if (left < right) {
int tmp = arr[left]; // 記錄基準數
int l = left;
int r = right;
while (l < r) {
// 從右往左找一個數小於基準數
// 1) 如果從右往左找到了一個數小於基準數(l < r)
// 2)如果從右往左未找到一個數小於基準數 (l = r)
while (l < r && arr[r] > tmp)
r--;
if (l < r)
arr[l++] = arr[r];
// 從左往右找一個數大於基準數
// 1.1)如果從左往右找到了一個數小於基準數(l < r)—— 還清債務
// 1.2)如果從左往右沒有找到一個數小於基準數 (l = r)—— 未還清債務
// 2)由於l = r,後面的代碼不執行(l = r)—— 表示基準數是最小值
while (l < r && arr[l] < tmp)
l++;
if (l < r)
arr[r--] = arr[l];
}
// 1)如果還清債務,左派收回擔保
// 1.2)如果未還清債務,由於此時l = r,且都在右派的缺口處,因此右派收回擔保
arr[l] = tmp;
quickSort(arr, left, l - 1);
quickSort(arr, l + 1, right);
}
}
public static void main(String[] args) {
int[] arr = {62, 56, 45, 46, 24, 43, 24, 28, 5, 44};
quickSort(arr);
for (int i : arr)
System.out.print(i + " ");
}
}
注意上面的
1)對應1.1)1.2)
2)對應2)