基礎演算法學習筆記
阿新 • • 發佈:2022-12-12
#筆記-基礎演算法
快速排序
將序列按從小到大或從大到小順序排序。
時間複雜度 \(O(nlogn)\),不穩定。
步驟
-
確定分界點 \(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)
。否則會有邊界問題(舉序列中只有兩個數的情況思考)。 -
調整區間:兩個指標 \(i,j\) 往中心移動,左邊遇到 \(\ge x\) 的數時停下,右邊遇到 \(\le x\)
為什麼不是“左邊遇到 \(> x\) 的數時停下,右邊遇到 \(< x\) 的數停下”呢?
-注意序列中所有數相同的情況。 -
遞迴求解左右兩段。
不難得出,當 \(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); }
例題
思路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); }