Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

これどうなる?

Slide 5

Slide 5 text

これどうなる?

Slide 6

Slide 6 text

こうなる $ 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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

ソートの仕様 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。

Slide 10

Slide 10 text

ソートの仕様 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エンジンが異なれば異なるソート アルゴリズムが使われる

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

計算量

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

バブルソート 配列をループして、隣接する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/

Slide 16

Slide 16 text

選択ソート 未整列データの中の最小値を探し、先頭 と入れ替える。最小値を整列済みデータ とする。ソートが完了するまでこれを繰り 返す。 - 平均計算量 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/

Slide 17

Slide 17 text

挿入ソート 未整列データから値を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/

Slide 18

Slide 18 text

マージソート 要素数が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/

Slide 19

Slide 19 text

クイックソート 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/

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

これどうなる?

Slide 26

Slide 26 text

ありがとうございました

Slide 27

Slide 27 text

参考 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/