$30 off During Our Annual Pro Sale. View Details »

ソートと計算量のはなし_in_JavaScript.pdf

okym
May 26, 2022
760

 ソートと計算量のはなし_in_JavaScript.pdf

okym

May 26, 2022
Tweet

Transcript

  1. ソートと計算量のはなし
    in JavaScript
    2021/11/04 社内勉強会
    okym-t

    View Slide

  2. 経緯
    ・チームメンバーと雑談してるときにソートの話が出た
    ・私のように大学でCSやっていない人はあまり知らないかも
    ・フロントエンドだけやってるとあまり意識してなかったかも
    ・あまり意識しなくていいとはいえ、全く知らないのもいまいちなのでまとめる
    ・あとタイムリーにもTwitterでソートと計算量の話で盛り上がってた

    View Slide

  3. ゴール
    ・計算量の概念と感覚をつかむ
    ・ソートの基本的なアルゴリズムいくつか知る

    View Slide

  4. これどうなる?

    View Slide

  5. これどうなる?

    View Slide

  6. こうなる
    $ time node sort.js
    計算量 時間
    1000 x 1000 x 1000 10^9 0.721 s
    10000 x 1000 x 1000 10^10 8.760 s
    10000 x 10000 x 1000 10^11 106.3 s
    10000 x 10000 x 10000 10^12 1396 s

    View Slide

  7. なにが問題か
    ・ここでは読みにくいとか、変数名とか、定数にとか、そもそもなんだこの処理はというのは
    置いておく
    ・計算量が小さい場合は問題なくても、大きくなるとパフォーマンスに多大な影響を与えて
    しまう
    ・いつのまにかAPIのレスポンスタイムが遅いけどなんでだってなる
    ・ロジックは正しいので計算量がそこそこのテストケースしか用意していなかったりすると
    テストでも検知しにくい

    View Slide

  8. 例えばソートの計算量はど
    んなもんか

    View Slide

  9. ソートの仕様
    ECMAScript2021 Language Specification より引用
    > The elements of this array are sorted. The sort must be stable (that is, elements that compare equal must
    remain in their original order). If comparefn is not undefined, it should be a function that accepts two
    arguments x and y and returns a negative value if x < y, zero if x = y, or a positive value if x > y.
    ・stable sort (※1)でなければならない (※2)
    ・比較関数は2つの引数を受け取って xyなら正を返す
    ※1 同等なデータのソート前の順序がソート後も保存されるもの
    ※2 ES2019以降の仕様。ES2015の仕様だとstableとは限らない。ただし V8(v7.0以降)のソートアルゴリズムは stableなので実装はstable。

    View Slide

  10. ソートの仕様
    ECMAScript2021 Language Specification より引用
    > The elements of this array are sorted. The sort must be stable (that is, elements that compare equal must
    remain in their original order). If comparefn is not undefined, it should be a function that accepts two
    arguments x and y and returns a negative value if x < y, zero if x = y, or a positive value if x > y.
    ・stable sort (※1)でなければならない (※2)
    ・比較関数は2つの引数を受け取って xyなら正を返す
    ※1 同等なデータのソート前の順序がソート後も保存されるもの
    ※2 ES2019以降の仕様。ES2015の仕様だとstableとは限らない。ただし V8(v7.0以降)のソートアルゴリズムは stableなので実装はstable。
    ・アルゴリズムの指定はない
    ・JSエンジンが異なれば異なるソート
    アルゴリズムが使われる

    View Slide

  11. JSエンジンとソート実装
    - V8(Chrome、Node.js)
    - v6以前:配列の要素数が10以下では挿入ソート、それ以上はクイックソート
    - v7以降:ティムソート
    - Chakra(IE、旧Edge)
    - 配列の要素数が512個より大きい場合はクイックソート、それ以下なら二分挿入ソート
    - SpiderMonkey(Firefox)
    - マージソート
    - JavaScriptCore(Safari)
    - 以前は選択ソート、いまはマージソート
    参考:https://memolog.org/2018/about-array-prototype-sort.html

    View Slide

  12. ソートアルゴリズム
    https://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%BC%E3%83%88

    View Slide

  13. 計算量

    View Slide

  14. 今回扱うソート
    - バブルソート
    - 選択ソート
    - 挿入ソート
    - マージソート
    - クイックソート
    https://git01.mdomain/takehiko.okayama/js-array-sort

    View Slide

  15. バブルソート
    配列をループして、隣接する2つの要素を
    比較する。一方の要素がもう一方より大
    きい場合入れ替える。
    - 平均計算量 O(n^2)
    - 最悪計算量 O(n^2)
    - stable
    https://medium-company.com/%e3%83%90%e3%83%96%
    e3%83%ab%e3%82%bd%e3%83%bc%e3%83%88/

    View Slide

  16. 選択ソート
    未整列データの中の最小値を探し、先頭
    と入れ替える。最小値を整列済みデータ
    とする。ソートが完了するまでこれを繰り
    返す。
    - 平均計算量 O(n^2)
    - 最悪計算量 O(n^2)
    - not stable ※
    ※ →の実装のように「minとi番目を入
    れ替える」とnot stable、「minとi番目の前
    に挿入して他を前にずらす」とstable
    https://medium-company.com/%e9%81%b8%e6%8a%9e%
    e3%82%bd%e3%83%bc%e3%83%88/

    View Slide

  17. 挿入ソート
    未整列データから値を1つ取り出す。取り
    出した値を整列済みデータの適切な位置
    に挿入する。ソートが完了するまでこれを
    繰り返す。
    - 平均計算量 O(n^2)
    - 最悪計算量 O(n^2)
    - stable
    https://medium-company.com/%E6%8C%BF%E5%85%A5
    %E3%82%BD%E3%83%BC%E3%83%88/

    View Slide

  18. マージソート
    要素数が1個になるまで配列を2分割して
    いく操作を繰り返して、細分化された要素
    同士をソートしながら戻す
    - 平均計算量 O(n log n)
    - 最悪計算量 O(n log n)
    - stable
    https://medium-company.com/%E3%83%9E%E3%83%BC
    %E3%82%B8%E3%82%BD%E3%83%BC%E3%83%88/

    View Slide

  19. クイックソート
    pivotとなる値を決め、それより大きい要
    素の集合と小さい集合に分け、集合単位
    でソートする操作を繰り返す
    https://en.wikipedia.org/wiki/Quicksor
    t#/media/File:Quicksort-diagram.svg
    - 平均計算量 O(n log n)
    - 最悪計算量 O(n^2)
    - not stable
    https://medium-company.com/%E3%82%AF%E3%82%A4%E
    3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%8
    8/

    View Slide

  20. クイックソート
    pivotとなる値を決め、それより大きい要
    素の集合と小さい集合に分け、集合単位
    でソートする操作を繰り返す
    https://en.wikipedia.org/wiki/Quicksor
    t#/media/File:Quicksort-diagram.svg
    - 平均計算量 O(n log n)
    - 最悪計算量 O(n^2)
    - not stable

    View Slide

  21. pivotはどうやって決めるべき?
    - クイックソートではその特性上pivotを適切に選択することが重要
    - pivotの選択をミスると最悪計算量になる
    - いくつかの要素をサンプリングしたうえでの中央値をpivotとすると、平均的なデータに対しては良好な性能
    を示すが、最悪計算量を保証するわけではない
    例としてV8は以下のような戦略をとっている
    ・pivotは並び替え対象の配列の最初、最後、および第3の要素の中央値として選択する。小さい配列の場合、第3
    要素は中央の要素。
    ・大きな配列の場合、サンプルを取得してソートし、その中央値を第3要素とする。
    https://github.com/v8/v8.dev/blob/main/src/blog/array-sort.md#history

    View Slide

  22. JSエンジンとソート実装
    - V8(Chrome、Node.js)
    - v6以前:配列の要素数が10以下では挿入ソート、それ以上はクイックソート
    - v7以降:ティムソート
    - Chakra(IE、旧Edge)
    - 配列の要素数が512個以下では場合は二分挿入ソート、それ以上はクイックソート
    - SpiderMonkey(Firefox)
    - マージソート
    - JavaScriptCore(Safari)
    - 以前は選択ソート、いまはマージソート
    参考:https://memolog.org/2018/about-array-prototype-sort.html

    View Slide

  23. 要素数でアルゴリズム変えてるのなんで?
    - クイックソートはパーティション分割後に 2回再帰呼び出しされる
    - ↑はスタックフレームを作成、破棄するオーバーヘッドがある
    - なので小さい配列に対しては挿入ソートの方が有利

    View Slide

  24. ゴール振り返り
    ・計算量の概念と感覚をつかむ
    ・ソートの基本的なアルゴリズムいくつか知る
    プロダクト開発でもいつか役立つときがくるかも

    View Slide

  25. これどうなる?

    View Slide

  26. ありがとうございました

    View Slide

  27. 参考
    https://www.ecma-international.org/wp-content/uploads/ECMA-262_12th_edition_june_
    2021.pdf
    https://github.com/v8/v8.dev/blob/main/src/blog/array-sort.md
    https://medium.com/devtechtoday/an-introduction-to-sorting-algorithms-in-javascript-a
    026ad84371f
    https://tech.preferred.jp/ja/blog/tim-sort/

    View Slide