1. 程式人生 > 其它 >基礎演算法學習筆記

基礎演算法學習筆記

#筆記-基礎演算法

快速排序

將序列按從小到大或從大到小順序排序。

時間複雜度 \(O(nlogn)\),不穩定。

步驟

  1. 確定分界點 \(x\)\(q[l]\)\(q[(l + r) \div 2]\)\(q[r]\)\(q[(l +r+1)\div 2]\)

    注意,上面分界點用列舉的前兩項時,遞迴處理 qsort(l, j); qsort(j + 1, r);反之遞迴處理 qsort(l, i); qsort(i + 1, r)。否則會有邊界問題(舉序列中只有兩個數的情況思考)。

  2. 調整區間:兩個指標 \(i,j\) 往中心移動,左邊遇到 \(\ge x\) 的數時停下,右邊遇到 \(\le x\)

    的數停下,再交換。

    為什麼不是“左邊遇到 \(> x\) 的數時停下,右邊遇到 \(< x\) 的數停下”呢?
    -注意序列中所有數相同的情況。

  3. 遞迴求解左右兩段。

    不難得出,當 \(i \ge j\) 時,\(i\) 左邊都為 \(\le x\) 的數,\(j\) 右邊都為 \(\ge x\) 的數,故分兩段遞迴即可。具體細節見上文。

程式碼如下:

void qsort(int l, int r) {
    if(l >= r) return;
    int x = a[(l + r) / 2], i = l - 1, j = r + 1;
    while(i < j) {
        do i++; while(a[i] < x);
        do j--; while(a[j] > x);
        if(i < j) swap (a[i], a[j]);
    }
    qsort(l, j); qsort(j + 1, r);
}

例題

acwing786 第k個數

思路1:將原陣列 \(a\) 排序後輸出 \(a[k]\) 即可。排序可 sort(),也可手寫。時間複雜度 \(O(nlogn)\)

思路2:看向快排模板。

快排分段遞迴時,我們拿到了陣列分界點的指標。因此,我們只需要在兩段中選擇 \(k\) 在內的一段進行遞迴排序即可。

時間複雜度計算 \(O(n + \frac{n}{2} + \frac{n}{4} + \dots) < O(2n) = O(n)\)

void qsort(int l, int r) {
    if(l >= r) return;
    int x = a[(l + r) / 2], i = l - 1, j = r + 1;
    while(i < j) {
        do i++; while(a[i] < x);
        do j--; while(a[j] > x);
        if(i < j) swap (a[i], a[j]);
    }
    if(k <= j) qsort(l, j); else qsort(j + 1, r);
}