快速排序是冒泡排序的改進版,也是最好的一種內排序,快速排序思想—-分治法也確實實用,因此很多軟件公司的筆試面試,包括像騰訊,微軟等知名IT公司都喜歡考這個,還有大大小的程序方面的考試如軟考,考研中也常常出現快速排序的身影。也是作爲程序員必須掌握的一種排序方法。
思想:1.在待排序的元素任取一個元素作爲基準(通常選第一個元素,但最好的選擇方法是從待排序元素中隨機選取一個作爲基準),稱爲基準元素;
2.將待排序的元素進行分區,比基準元素大的元素放在它的右邊,比其小的放在它的左邊;
3.對左右兩個分區重複以上步驟直到所有元素都是有序的。
所以我是把快速排序聯想成東拆西補或左拆右補,一邊拆一邊補,直到所有元素達到有序狀態。也有人稱之爲 挖坑(拆)填數(補)+分治法(基準 元素的 左側 和右側 分別按照 左拆右補的方法)
圖解:
初步實現:
public int quickSort(int arr[], int _left, int _right) {
int baseTemp = arr[_left];// 基準元素
while (_left < _right) {
// 從右向左 開始置換 拆右補左
while (_right > _left && arr[_right] >= baseTemp) _right--;
if (_left < _right) arr[_left++] = arr[_right];
// 從左向右 開始置換 拆左補右
while (_left < _right && arr[_left] <= baseTemp) _left++;
if (_left < _right) arr[_right--] = arr[_left];
}
//退出時,_left等於_rigth。將baseTemp填到這個坑中。基準元素歸位
arr[_left] = baseTemp;
return _left;
}
// 分治法 基準元素的左側 和 基準元素的右側
public void quickSortRecursion(int arr[], int _left, int _right) {
int base = quickSort(arr, _left, _right);
if (_left < _right) {
// 對 基準元素的 左側 進行 遞歸排序
quickSortRecursion(arr, _left, base - 1);
quickSortRecursion(arr, base + 1, _right);
}
}
精簡優化代碼:
public static void quickSortBetter(int arr[], int _left, int _right) {
int left = _left;
int right = _right;
if (left < right) { //待排序的元素至少有兩個的情況
int temp = arr[left]; //待排序的第一個元素作爲基準元素
while (left < right) { //從左右兩邊交替掃描,直到left = right
while (right > left && arr[right] >= temp)
right--; //從右往左掃描,找到第一個比基準元素小的元素
arr[left++] = arr[right]; //找到這種元素arr[right]後與arr[left]交換
while (left < right && arr[left] <= temp)
left++; //從左往右掃描,找到第一個比基準元素大的元素
arr[right--] = arr[left]; //找到這種元素arr[left]後,與arr[right]交換
}
arr[left] = temp; //基準元素歸位
quickSortBetter(arr, _left, left - 1); //對基準元素左邊的元素進行遞歸排序
quickSortBetter(arr, right + 1, _right); //對基準元素右邊的進行遞歸排序
}
}
算法分析:
1.當分區選取的基準元素爲待排序元素中的最大或最小值時,爲最壞的情況,時間複雜度和直接插入排序的一樣,移動次數達到最大值 Cmax = 1+2+…+(n-1) = n*(n-1)/2 = O(n^2) 此時最好時間複雜爲O(n^2)。
2.當分區選取的基準元素爲待排序元素中的”中值”,爲最好的情況,時間複雜度爲O(nlog2n)。
3.快速排序的空間複雜度爲O(log2n).
4.當待排序元素類似[6,1,3,7,3]且基準元素爲6時,經過分區,形成[1,3,3,6,7],兩個3的相對位置發生了改變,所是快速排序是一種不穩定排序。