エムスリーエンジニアリンググループ AI・機械学習チームでソフトウェアエンジニアをしている中村(po3rin) です。検索とGoが好きです。
最近、Go1.19でsortパッケージのアルゴリズムが一部変更されました。
1.19リリースノートではPattern-defeating Quicksortが採用されたと紹介があります。実際にsort/zsortfunc.go、sort/zsortinterface.goにそれぞれpdqsort_func、pdqsortという関数があります。
// pdqsort sorts data[a:b]. // The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort. // pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf // C++ implementation: https://github.com/orlp/pdqsort // Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/ // limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort. func pdqsort(data Interface, a, b, limit int)
今回はPattern-defeating Quicksortがどのようなアルゴリズムなのかを論文*1を読んで、実際にGoでどのように使われているかを調べてみました。
この記事ではPattern-defeating Quicksortのざっくりとした理解を目的とし、証明など細かい話はスキップしてなんとなく何をやってるのかの理解を目指します。
Pattern-defeating Quicksortはクイックソートが苦手な同じ値を持つシーケンスに対して効力を発揮します。実用では大量の被りがある値のソートがほとんど(カテゴリでソートするとか)なので、実用面でも非常に有用なアルゴリズムです。
この論文の貢献として、k個の異なる要素を持つ入力に対してO(nk)の最悪ケースに収まる3 方向比較手法を提案しており非常に面白いです。
論文はこちらです。
続きを読む