Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DIVE INTO Slices Sort

DIVE INTO Slices Sort

DMM.go#8で登壇した際の発表資料です

connpass
- https://dmm.connpass.com/event/322113/

Avatar for Kazuki Isogai

Kazuki Isogai

July 23, 2024
Tweet

Other Decks in Technology

Transcript

  1. © DMM © DMM CONFIDENTIAL DIVE INTO Slices Sort pdqsort

    アルゴリズム , slices.Sort と sort.Sort の違い 24新卒 磯貝 和希 (いっそ) 2024.07.23 DMM.go #8
  2. © DMM 2 自己紹介 DIVE INTO Slices Sort 磯貝 和希

    (ISOGAI KAZUKI) - ニックネーム: いっそ - 経歴: 2024年 新卒入社 (学部) - 配属: 動画配信開発部 プロダクトグループ リニューアルチーム (予定) - 職種: サーバーサイド (予定) - 趣味: ゲーム (過去一番プレイしたゲーム: Minecraft) ソーシャル - GitHub: isso-719 - X (旧 Twitter): @isso_app
  3. © DMM 3 アジェンダ DIVE INTO Slices Sort 本発表の目的: slices

    pkg の Sort 関数を 2 つ視点から深掘りして理解を深める 1. pdqsort アルゴリズム a. 弱み: quicksort の特定パターンの場合に計算量が大きくなる b. pdqsort は quicksort の弱みを insertion sort, heapsort でカバーしたもの c. pdqsort はなるべく “最悪のケース” が起こらないようにしている 2. slices pkg と sort pkg の Sort の違い a. slices pkg と sort pkg には ほぼ同じ関数がある b. slices pkg の Sort には Generics が使用されている c. Go「より新しい slice.SortFunc 関数の方が人間工学的で速く実行できます」
  4. © DMM pdqsort (Pattern-defeating sort) とは... quicksort の弱みを insertion sort,

    heapsort でカバー ※ quicksort, insertion sort, heapsort の知識があるとわかりやすいです 4
  5. © DMM 2, 8, 9, 1, 3, 5 [1, 2],

    [8, 9, 3, 5] => p=0.33 (= 2/6) 最悪計算量 O(n2) 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 [1], [2, 3, 4, 5, 6, 7, 8, 9, 10] => p=0.1 (= 1/10) 5 弱み: quicksort の特定パターンの場合に計算量が大きくなる DIVE INTO Slices Sort ソート済や同じ要素の多い slice は計算量が大きい 左右均等のパーティションに分けると計算量小さい 最悪計算量 O(n2) 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 [1], [2, 3, 4, 5, 6, 7, 8, 9, 10] [1], [2], [3, 4, 5, 6, 7, 8, 9, 10] [1], [2], [3], [4, 5, 6, 7, 8, 9, 10] … 平均計算量 O(nlogn) 2, 8, 9, 1, 3, 5 [1, 2], [8, 9, 3, 5] [1], [2], [3, 5, 8], [9] quicksort ピボットパーセンタイル p = 分けた後のピボット位置 / 分ける前の要素数 0 ≦ p ≦ 0.5, 0.5 に近づくほど良い ※左端を固定ピボットとした場合
  6. © DMM 6 pdqsort は quicksort の弱みを insertion sort, heapsort

    でカバーしたもの DIVE INTO Slices Sort 常に O(nlogn) の計算量, もしくは処理時間が早い選択肢をとっている *: 要素数 n として、ピボットパーセンタイル 0.125 未満が log 2 n 回以上 小さな配列 の 処理時間が早い 常に O(nlogn) 一般的に処理時間 は quicksort に劣る 平均 O(nlogn), 最悪 O(n2)
  7. © DMM 7 pdqsort はなるべく “最悪のケース ” が起こらないようにしている slice の扱い方やピボットの取り方も工夫

    不均衡なパーティション分けが発生したら 配列をシャッフル (breakPatternsOrdered) 3分割パーティショニング手法 を使用して重複要素が多い場合に対処 (小, 同, 大 に分ける) 増加・減少ヒントの使用でデータが既に増加順または減少順に近い場合の最適化 要素数に応じたピボット選択 - 小さい配列では固定ピボットを使用 (要素数 < 8) - 中規模な配列では median-of-three (中央値の三分割) 法を使用 (8 <= 要素数 < 50) - 大規模な配列では Tukey ninther (トゥーキー・ナインス) 法を使用 (要素数 >= 50) => なるべく heapsort を使用しない DIVE INTO Slices Sort 時間都合のため詳しい説明略
  8. © DMM 8 Go Bench で比較してみた DIVE INTO Slices Sort

    quick sort pdq sort quick sort pdq sort 1. 要素数 10,000 のランダムな int slice 2. 要素数 10,000 のソート済な int slice Code: github.com/isso-719/dmm-go-8-sort-bench
  9. © DMM pdqsort (Pattern-defeating sort) とは... quicksort の弱みを insertion sort,

    heapsort でカバー しつつ、色々工夫されている!
  10. © DMM 11 slices pkg と sort pkg には ほぼ同じ関数がある

    DIVE INTO Slices Sort pdqsort を使用しているところも同様 slices pkg の方が少しだけ直感的で呼び出ししやすい slices.Sort slice := []int{3, 2, 1} slices.Sort(slice) sort.Sort slice := []int{3, 2, 1} sort.Sort(sort.IntSlice(slice)) slices.SortFunc slice := []int{3, 2, 1} slices.SortFunc(slice, func(x, y int) int { return cmp.Compare(a, b) }) sort.Slice slice := []int{3, 2, 1} sort.Slice(slice, func(i, j int) bool { return slice[i] < slice[j] })
  11. © DMM 12 slices pkg の Sort には Generics が使用されている

    DIVE INTO Slices Sort Generics 使用により、プログラムの再利用性と型安全性が高まる 受け取る型に cmp.Ordered (基本型の集合) を使用して、あらかじめ型がわかっている状態に sort pkg は interface{} や any で要素をとるため、動的に型チェックするためのメモリが必要
  12. © DMM 13 Go「ほとんどの場合より新しい slice.SortFunc 関数の方が人間工学的で速く実行できます」 DIVE INTO Slices Sort

    Go のソースコードにも slices pkg の使用をオススメする記述がある => 今後 slices pkg で slice ソートをするのがスタンダードに?
  13. © DMM 15 まとめ DIVE INTO Slices Sort - slices

    pkg の Sort 関数には pdqsort が採用 - pdqsort は quicksort の弱みを insertion sort, heapsort でカバーしたもの - なるべく “最悪のケース” が起こらないようにもしている - slices pkg と sort pkg の Sort の違い - slices.Sort と sort.Sort を比較 - slices pkg の方が呼び出しやすい - slices pkg は Generics を使用している - 再利用性と型安全性が高まり、型チェックのためのメモリも取らない - 人間工学的なのと速度の点で slices の sort が今後のスタンダードになりそう? - slice pkg 使っていきましょう! - Go 1.21 以降の OSS で sort.Sort を使用していたら Contribute Chance! あるかも?