第3節、時間和空間的均衡——快速排序
阿新 • • 發佈:2018-05-19
算法 快速排序 1、引入
第一節講的計數排序有很好的運行時間表現,但因為占用空間的問題,只適用於數字非常有限的情況;
第二節講的冒泡排序解決了計數排序空間的問題,但時間復雜度卻變成了O(n^2)。
對冒泡排序的過程進行分析,我們可以發現,在每一輪的排序過程中,需要對所有相鄰的數字進行比較(當然,除了最後幾個最大數字),有的數字第一輪比較過了,第二輪可能還要比較,這就存在了優化的空間。
針對這個重復比較的問題,快速排序提出了基準數,減小比較次數,實現了算法的優化。
快速排序的過程:
1、選擇一個數作為基準數,也就是比較的標準
2、比這個數字小的放左邊,大的放右邊
3、再對左右區間重復第二步,直到各區間只有一個數
這種重復左右區間直至一個終止條件的方式,就是分治或者遞歸的過程,所以快速排序算法也叫做分治算法,可以簡單理解為分為左右兩部分,分別求解。
分治和遞歸的聯系和區別,之後會在《算法思想》中說明,這裏可以簡單理解為遞歸是實現分治的方法。
2、核心算法
下面一個動態表現了快速排序的過程
快速排序的過程也是一個分治或者遞歸的過程,因為需要遞歸,即函數調用自身,只是參數不一樣,所以需要單獨寫一個函數。
-
遞歸函數內部首先就要設置終止條件,具體到快速排序,就是最終只剩下一個數,自然就排序完成了,就不用再遞歸了;
-
while循環內部就是主體,從左到右找到比基準數大的,從右到左找到比基準數小的,交換位置,直至兩個過程相遇;循環完成之後將基準數歸位
- 左邊和右邊分別遞歸
核心代碼如下,使用C語言:
//快速排序 void quicksort(int left, int right) { int i, j, temp; //終止條件 if (left>right) return; temp = a[(left + right) / 2]; i = left; j = right; //從左到右找到比基準數大的,從右到左找到比基準數小的,交換位置,直至兩個過程相遇即全部比較完成 while (i != j) { while (a[j] >= temp && i<j) j--; while (a[i] <= temp && i<j) i++; if (i < j) { int l = a[i]; a[i] = a[j]; a[j] = l; } } //將基準數歸位 a[(left + right) / 2] = a[i]; a[i] = temp; //左邊遞歸過程 quicksort(left, i - 1); //右邊遞歸過程 quicksort(i + 1, right); }
3、代碼
這裏是完整代碼,使用C語言
//輸入:6 5 3 1 8 7 2 4
//輸出:1 2 3 4 5 6 7 8
#include <stdio.h>
using namespace std;
int a[100001];
//快速排序
void quicksort(int left, int right) {
int i, j, temp;
//終止條件
if (left>right)
return;
temp = a[(left + right) / 2];
i = left;
j = right;
//從左到右找到比基準數大的,從右到左找到比基準數小的,交換位置,直至兩個過程相遇即全部比較完成
while (i != j) {
while (a[j] >= temp && i<j)
j--;
while (a[i] <= temp && i<j)
i++;
if (i < j) {
int l = a[i];
a[i] = a[j];
a[j] = l;
}
}
//將基準數的位置放在大小分割的中間
a[(left + right) / 2] = a[i];
a[i] = temp;
//左邊遞歸過程
quicksort(left, i - 1);
//右邊遞歸過程
quicksort(i + 1, right);
}
int main() {
int n=8;
//讀入數據
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
//快速排序
quicksort(1, n);
//輸出結果
for (int i = 1; i <= n; i++)
printf("%d ", a[i]);
getchar(); getchar();
return 0;
}
4、後續
至此,計數排序、冒泡排序、快速排序的就全部完成了,你學會了嗎?具體掌握還需要加強練習,下一節,我們通過習題,鞏固學習!
第3節、時間和空間的均衡——快速排序