並行排序演算法:雙調排序

dcytrl發表於2024-11-15

引入

有一個排列,你可以透過“比較並交換”這個操作將該排列排好序,即,每次選擇一對數 \((i,j)\),若 \(a_i>a_j\) 則交換,否則不交換。

但是,你可以把多對 \((i,j)\) 放在一次操作裡並行“比較並交換”,此時運算元記 1,與數對的對數無關,但是每個 \(i\) 只能出現至多一次。要求運算元最小。

定義

雙調序列:先單增後單減,或者先單減後單增。即,單峰數列或單谷數列。

演算法流程

定理:設一個長度為 \(2^k\) 的序列 \(\{a_i\}\),將該序列劈成兩半,然後將兩個序列的對應位置 \((i,i+2^{k-1})\) 執行“比較並交換”,則操作結束後兩個序列也都是雙調序列。

考慮 01 序列,顯然序列形如 001100 或者 110011,不妨設其為 001100,分類討論一下中點落在哪即可。對於一般情況,對於所有 \(x\),令 \(b_i\leftarrow [a_i\le x]\) 就轉化為了 01 序列問題。

那麼如果我們想要把一個雙調序列排序的話,根據定理我們就可以將 \(2^k\) 的問題劃分成兩個 \(2^{k-1}\) 的獨立子問題,遞迴下去即可。由於分治的每一層每個節點相互獨立,所以雙調序列排序可以在 \(O(\log n)\) 次操作內完成。

考慮將一般序列排序。還是考慮分治,假設我們已經將 \(a_{[1,2^{k-1}]},a_{(2^{k-1},2^k]}\) 排好序,那麼將後一半序列翻轉一下,就轉化成了雙調序列了。實現中,為了實現翻轉,只需要把 \((i,i+2^{k-1})\) 操作變成 \((i,2^k-i+1)\) 即可。同理,每一層的點還是相互獨立,一般序列排成雙調序列也可以在 \(O(\log n)\) 的時間內完成。

故總操作次數為 \(O(\log^2n)\)。由於該排序常規時間複雜度 \(O(n\log^2n)\),故在常規排序中不實用。

相關文章