レッスン
理論 — 二分ヒープ:配列でつくる優先度付きキュー
二分最小ヒープは、どの位置 i でも、そこのキーが位置 2i + 1 と 2i + 2 にある子のキー以下になっている配列です。位置 i の親は ⌊(i − 1) / 2⌋ にあります。この関係で配列を読むと完全二分木になり、最小のキーは常に位置0、つまり根にあります。挿入では、キーを末尾に加えて上方修正します。親より小さい間、親と交換して上へ移す操作です。最小値を取り出すときは、末尾のキーを根に移して下方修正します。子のうち小さいほうが自分より小さければ、その子と交換して下へ移します。このように使うヒープは、優先度付きキューとして働きます。
各記号の意味
n- ヒープ内のキーの個数
i- 0から数えた配列内の位置
h- その位置の高さ:下に何段あるかを表す値、⌊log₂(n / (i + 1))⌋
- 前提
- 比較とは、キーどうしの大小を一度調べることです。交換は、二つの位置のキーを入れ替えること。最小値を取り出す際に末尾のキーを根へ移す操作は、どちらにも数えません。キーが親、または小さいほうの子と等しければ、その場にとどまります。子どうしが等しい場合は左の子を選びます。ここでは最小のキーを根に置きますが、比較の向きをすべて逆にすれば最大ヒープになります。スマートフォンでも木全体を見られるよう、キーは0〜99の値で最大15個としています。表の最終行では、すべて異なるキーの並べ方を数えています。
全プロセスの詳細解説
-
キーが千個ほどになると、構築に何回の比較が必要? 4 ステップ
大きい順・一つずつ挿入、大きい順・最後の親から調整を順に押し、比較回数が34回と22回になる理由を説明しましょう。では、1,023個のキーが大きい順に届く場合、それぞれ何回の比較が必要でしょうか。
-
位置 i の深さは ⌊log₂(i + 1)⌋ です。深さ0には1個、深さ1には2個、深さ2には4個、深さ3には8個の位置があります。大きい順に届くと、新しいキーは常にそれまでの最小値なので根まで上がり、1段につき比較と交換が各1回必要です。したがって、0 + 2 · 1 + 4 · 2 + 8 · 3 = 34 となります。
-
最後の親から構築するときに効くのは、高さです。根の高さは3、位置1と2は2、深さ2の4個は1、葉の8個は0で、合計11。大きい順なら、どのキーも下がれるところまで下がります。15個ではどの親にも子が2個あるため、1段につき比較は2回。比較22回、交換11回になります。
-
1,023 = 2¹⁰ − 1 なので、全10段が埋まった二分木になり、深さ d には 2ᵈ 個の位置があります。逐次挿入の比較回数は深さの合計で、1 · 2 + 2 · 4 + 3 · 8 + ⋯ + 9 · 512 = 8,194 回。交換も同じ回数です。
-
最後の親から構築する場合、比較回数は高さの合計の2倍です。高さ0の位置が 2⁹ 個、高さ1が 2⁸ 個と続き、根の高さは9。高さの合計は 1 · 256 + 2 · 128 + ⋯ + 9 · 1 = 1,013 で、1,023からその二進表記に含まれる10個の 1 を引いた値に等しくなります。その2倍で比較は2,026回、交換は1,013回です。
解答
一つずつ挿入すると比較8,194回、最後の親から調整すると2,026回です。キーあたりでは、およそ8回と2回。ヒープ内の位置の多くは深さが大きく、高さは小さいため、深さに応じて手間のかかる逐次挿入と、高さに応じて手間のかかる最後の親からの構築で差がつきます。このツールで扱えるのは15個までですが、同じ計算で画面の34回と22回が得られます。
-
学習の道すじ
データ構造が得意なこと
参考文献 (2)
- Heapsort as first published: J. W. J. Williams, "Algorithm 232: Heapsort," Communications of the ACM 7(6), 347–348, June 1964.
- The heap-based sort published six months later, close to the version used today: Robert W. Floyd, "Algorithm 245: Treesort 3," Communications of the ACM 7(12), 701, December 1964.