千磨萬擊還堅韌,任爾東西南北風
阿新 • • 發佈:2018-12-31
快速排序
快速排序的基本思想是通過劃分子陣列實現的,對於陣列A[p…r],劃分子陣列後得到一個索引q,使得A[p…q-1]子陣列的值都小於A[q],A[q+1…r]子陣列的值都大於等於A[q]。子陣列劃分後,再通過相同的方法遞迴處理兩個子陣列,最終達到整個陣列排序的目的。
快速排序虛擬碼
先看下虛擬碼:
quick_sort(A, p, r)
if (p < r)
int q = partition(A, p, r);
quick_sort(A, p, q - 1);
quick_sort(A, q + 1, r);
虛擬碼的思路很簡單,快速排序最重要的是劃分子陣列,即partition的實現,先看下partition示意圖
劃分子陣列過程中將陣列分為四個區域,首先將A[r]=x選為主元,劃分子陣列結束後A[q]的值就是x,即將陣列劃分為小於x和不小於x的兩個部分。
- 區域1:這個區域的值小於x
- 區域2:這個區域的值大於等於x
- 區域3:這個區域的值和x大小是未知的,是將要消除的區域
- 區域4:主元
劃分子陣列虛擬碼
劃分子陣列的過程即是消除區域3的過程,最終指標j等於r,看下partion的虛擬碼:
partition(A, p, r)
x = A[r]
i = p - 1
for j = p to r - 1
if A[j] < x
i = i + 1
exchange(A[i], A[j])
exchange(A[i+1], A[r])
return i + 1
根據quick_sort和partion的虛擬碼,很容易寫出java程式碼:
public class QuickSort {
/**
* 快速排序
* @param arr 待排序的陣列
* @param left 起始索引
* @param right 結束索引
*/
public static void quickSort(int[] arr, int left, int right) {
if (left < right) {
int q = partition(arr, left, right);
quickSort(arr, left, q - 1);
quickSort(arr, q + 1, right);
}
}
/**
* 劃分子陣列,返回值為q,則arr[left...q-1]子陣列的值都小於arr[q],
* arr[q+1...right]子陣列的值都不小於arr[q]
* @param arr
* @param left
* @param right
* @return
*/
private static int partition(int[] arr, int left, int right) {
int i = left - 1;
int x = arr[right];
for (int j = left; j < right; j++) {
if (arr[j] < x) {
i++;
exchange(arr, i, j);
}
}
exchange(arr, i + 1, right);
return i + 1;
}
private static void exchange(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
複雜度分析
空間複雜度:
快速排序的時間效能取決於劃分的效能,如果每次劃分都將子陣列劃分為差不多相等的兩部分,那麼排序效能會非常好,此時時間複雜度為
如果每次劃分都將陣列劃分為大小為n-1和0的子陣列時,此時排序效能會非常差,時間複雜度為
最壞時間複雜度:
最好時間複雜度:
平均時間複雜度: