標簽: 算法基礎
1. 算法簡介
快速排序,正如其名字一樣,是排序算法中速度較快的一種排序,算法復雜度為\(O(n*logn)\)。
排序過程中會打亂元素的相對位置,是不穩定排序。
算法思想:選定一個pivot,把元素分為兩組,一組比pivot小,一組比pivot大,然后按照相同的方法處理這兩組元素,是一個遞歸的過程。
算法核心是partition方法,即把元素分開兩組的方法,每次把元素平均分到兩邊時,算法效率最高。相反,如果每次partition把元素完全分到一邊,是最差情況,算法退化為\(O(n^2)\)。
下面詳細介紹兩種partition方法。假設需要排序的數組為: 21, 34, 74, 3, 20, 2, 56, 46, 6。
2. partition1方法
先把選定為pivot的元素放到最后,然后設定指針low和指針high,low指針左移,high指針右移,當兩個指針相撞后停止移動。期間如果符合交換條件,兩元素交換。最后把pivot元素放到中間。
這里選擇數組第一個元素作為pivot。
代碼:
/**
* @arr 待排序的數組
* @begin 需要partition的起始下標
* @end 需要partition的末尾下標
* @return 返回pivot所在位置下標
*/
int partition1(int arr[], int begin, int end) {
int pivotIndex = begin;
int pivot = arr[pivotIndex];
swap(arr, pivotIndex, end);
int low = begin;
int high = end;
while (low < high) {
// 因為把pivot放在了最后,所以low指針先走
while (low < high && arr[low] < pivot) low++;
while (low < high && arr[high] > pivot) high--;
if(low < high) swap(arr, low, high);
}
swap(arr, low, end);
return low;
}
3. partition2方法
類似冒泡排序的思路,把比pivot大的元素“往下沉”,把比pivot小的元素“往上浮”。
代碼:
/**
* @arr 待排序的數組
* @begin 需要partition的起始下標
* @end 需要partition的末尾下標
* @return 返回pivot所在位置下標
*/
int partition2(int arr[], int begin, int end){
int pivotIndex = begin;
int pivot = arr[pivotIndex];
swap(arr, pivotIndex, end);
int big = begin - 1; // index of smaller element
for (int small = begin; small <= end - 1; small++){
// 遇到一個元素小於pivot
if (arr[small] <= pivot){
big++;
swap(arr, big, small);
}
}
swap(arr, big + 1, end);
return big + 1;
}
4.快速排序代碼
void quickSort(int[] arr, int begin, int end) {
if (begin < end){
int p = partition1(arr, begin, end);
// int p = partition2(arr, begin, end);
quickSort(arr, begin, p - 1);
quickSort(arr, p + 1, end);
}
}
public static void main(String []argc){
int []array = {21, 34, 74, 3, 20, 2, 56, 46, 6};
quickSort(array, 0, array.length - 1);
}
5. 算法優化
- 在遞歸到規模比較小時,使用選擇排序/插入排序代替。
- 選取一個比較靠譜的pivot。(取first,取last,取middle,取三者的中)
- 使用循環代替遞歸。