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

Python でヒープ - heapq の概要

domodomodomo
March 17, 2019
270

Python でヒープ - heapq の概要

domodomodomo

March 17, 2019
Tweet

Transcript

  1. 0 2 4 1 3 6 5 左の子は 2n +

    1 2n + 1 2n + 1 2n + 1
  2. 0 2 4 1 3 6 5 右の子は 2n +

    2 2n + 2 2n + 2 2n + 2
  3. 0 2 4 1 3 6 5 親は n //

    2 n // 2 n // 2 n // 2 n // 2 n // 2 n // 2
  4. 2 4 3 6 5 1 _shi>up 子の要素 5, None

    のうち小さい方 5 と…
  5. 5 4 3 6 2 1 _shi>up 入れ替え 疑問1 1つ前の段階で完了しているのに、

    なぜこのようなことをしているのでしょうか?
  6. heappush _shi>down _shi>up heappop _shi>down heappush は _shi>down を呼び出す。 heappop

    は _shi>up を呼び出す。 _shi>up は shi>down を呼び出す。
  7. 6 4 2 5 3 1 0 _shi>up _shi>up _shi>up

    末尾の要素から根に向けて _shi>up 関数を 順番に実行していきます。
  8. 6 0 5 2 3 1 4 1. 2つのヒープを 2.

    新しい要素で 結合する 3. _shi>up を実行する。 考え方
  9. pos にある要素 2 つの子は、すでに ヒープなっています、また pos にあ る要素も含めてヒープにしたいと考 えています。そうするために pos

    に ある要素の小さい方の子を葉に当 たるまで (そしてその子の子などと 同様に) バブリングしてから、 _si>down を使用して、もともと pos のところにあった要素を正しい位置 に移動します。 The child indices of heap index pos are already heaps, and we want to make a heap at index pos too. We do this by bubbling the smaller child of   pos up (and so on with that child's children, etc) unNl hiOng a leaf, then using _si>down to move the oddball originally at index pos into place.
  10. heap pop をしている間、最後の配列 の要素は根に移動してきます、そし てその要素の値は大きくなる傾向が あります、そのため根から始まる一 連の値と比較しても、大抵効果があ りません(= 大抵の場合、ループから 早く抜け出させてはくれません)

    Knuth の第 3 巻を参照してください、 演習の中で、このことが説明され定 量化されています。 During a heap pop, the last array element is si>ed in, and that tends to be large, so that comparing it against values starNng from the root usually doesn't pay (= usually doesn't get us out of the loop early). See Knuth, Volume 3, where this is explained and quanNfied in an exercise. 葉の値を根に持ってきても値は大きいので、 途中で break させようとしても、かなり下まで行かなと break できないので意味がないということかな…
  11. これらのルーチンには配列要素から 「優先順位」を抽出する方法がない ため、比較の回数を減らすことが重 要です。なぜならコツとなるところは、 カスタム比較メソッドやタプル (優先 順位, 記録) を格納する配列要素に 隠れている可能性があるからです。

    したがって、比較は潜在的に高価で あると言えます。 CuOng the # of comparisons is important, since these rouNnes have no way to extract "the priority" from an array element, so that intelligence is likely to be hiding in custom comparison methods, or in array elements storing (priority, record) tuples. Comparisons are thus potenNally expensive. int 型の比較ならそうでもないですが 比較演算子を定義したユーザ定義クラスだと 比較の処理が重くなる “可能性” があるということかな。
  12. 長さ 1000 のランダムな配列では、こ の変更によって heapify() による比 較の数は少しだけ削減でき、網羅的 な heappop() による比較の数は大

    幅に削減されました、理論に沿って。 これは 3 回の実行からの典型的な 結果です(分散がどれほど小さいか を示すためだけに3 回)。 On random arrays of length 1000, making this change cut the number of comparisons made by heapify() a li^le, and those made by exhausNve heappop() a lot, in accord with theory. Here are typical results from 3 runs (3 just to demonstrate how small the variance is): よくわからない… コードを修正した時の 修正前と修正後の話をしてるのかな 「この変更」 “this change” ってなに?
  13. Compares needed by heapify Compares needed by 1000 heappops --------------------------

    -------------------------------- 1837 cut to 1663 14996 cut to 8680 1855 cut to 1659 14966 cut to 8678 1847 cut to 1660 15024 cut to 8703 よくわからない… コードを修正した時の 修正前と修正後の話をしてるのかな
  14. Building the heap by using heappush() 1000 Nmes instead required

    2198, 2148, and 2219 compares: heapify() を使用すると、 より効率的です。 Building the heap by using heappush() 1000 Nmes instead required 2198, 2148, and 2219 compares: heapify() is more efficient, when you can use it. よくわからない… ただ heappop より heapify で整列させた方が 効率的だという文章は収穫かな…
  15. 同じリストで list.sort() が必要とす る比較の合計は8627、8627、および 8632でした(これは heapify() と heappop() の比較の合計と比較す る必要があります)。

    list.sort() は (驚くことではありませんが!) より 効率的です。 The total compares needed by list.sort() on the same lists were 8627, 8627, and 8632 (this should be compared to the sum of heapify() and heappop() compares): list.sort() is (unsurprisingly!) more efficient for sorNng. Python の sort には TimSort という アルゴリズムが使われているらしいです。 それと比較したらという話をしているのでしょうか。