快速排序(模板題)
Acwing 785
給定你一個長度爲n的整數數列。
請你使用快速排序對這個數列按照從小到大進行排序。
並將排好序的數列按順序輸出。
輸入格式
輸入共兩行,第一行包含整數 n。
第二行包含 n 個整數(所有整數均在1~109
範圍內),表示整個數列。
輸出格式
輸出共一行,包含 n 個整數,表示排好序的數列。
數據範圍
1≤n≤100000
輸入樣例:
5
3 1 2 4 5
輸出樣例:
1 2 3 4 5
快排模板
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[(l + r)/2];
while (i < j)
{
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j), quick_sort(q, j + 1, r);
}
這種方式會將數組劃分爲小於等於和大於等於pivot 的左右兩部分,並且每一部分都不會爲空,因爲每次遞歸的時候數組的長度都會變小從而確保不會死循環。如果每次都選取數組最左邊的元素來作爲pivot,當數組已經是有序的時候每次遞歸數組的長度只會減少一,導致時間複雜度變爲 O(n2)
,這可以通過選中間元素作爲pivot或者每次隨機選取數組中一個元素與最左邊的元素交換來解決。注意這裏不能用最右邊的元素作爲pivot,這樣如果數組最右邊是最大元素的話會導致劃分完[l, j]不變導致死循環。
由於劃分完成後pivot不一定在這兩部分的分界線上,所以在做比如得到第k大的數這種題目時不能用j - l + 1 == k來判斷q[j]爲第k大的數,因爲左半區間只保證了所有數小於等於 pivot,而不一定都小於等於q[j]。
題解
#include<iostream>
using namespace std;
const int N = 100010;
int a[N];
void quick_sort(int q[],int l,int r)
{
if(l>=r) return;
int i=l-1,j=r+1,x=q[(l + r)/2];
while(i<j){
do i++ ; while(q[i]<x);
do j-- ; while(q[j]>x);
if(i<j) swap(q[i],q[j]);
}
quick_sort(q,l,j),quick_sort(q,j+1,r);
}
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; ++ i) cin >> a[i];
quick_sort(a,0,n-1);
for (int i = 0; i < n; ++ i) cout << a[i] << ' ';
return 0;
}