web-dev-qa-db-ja.com

いつヒープを使用したいですか?

優先度キューの明確な答えに加えて、プログラミングアドベンチャーでヒープが役立つのはいつですか?

80
Mithrax

最も大きい(または最も小さい)アイテムにすばやくアクセスする必要がある場合は常に使用します。これは、そのアイテムが常に配列の最初の要素またはツリーのルートにあるためです。

ただし、配列の残りの部分は部分的に並べ替えられません。したがって、インスタントアクセスは、最大(最小)のアイテムにのみ可能です。挿入は高速であるため、着信イベントまたはデータを処理し、常に最も早い/最も大きいものにアクセスするのに適した方法です。

優先キュー、スケジューラー(最も早いアイテムが必要な場合)などに役立ちます...

ヒープは、親ノードの値がその子孫ノードの値よりも大きいツリーです。

ヒープを、深さによる線形の順序で格納されたバイナリツリーと考えた場合、ルートノードが最初(次にそのノードの子、次にそれらのノードの子)になります。インデックスNのノードの子は2N + 1と2N + 2にあります。このプロパティにより、インデックスによる迅速なアクセスが可能になります。また、ヒープはノードの交換によって操作されるため、インプレースソートが可能になります。

110
Joe Koberg

ヒープは、最小または最大にすばやくアクセスできるようにするための構造です

しかし、なぜそれが必要なのでしょうか? addのすべてのエントリをチェックして、最小か最大かを確認できます。この方法では、常に一定の時間で最小または最大のO(1)を使用できます。

答えは、ヒープを使用すると、最小または最大を引き出して、次の最小または最大をすぐに知ることができるであるためです。それが優先キューと呼ばれる理由です。

実世界の例(ただし、あまり公平ではない):

患者が年齢に基づいて参加している病院があるとします。一番古い人は、いつキューに入れても、常に最初に参加します。

最も古いものを追跡することはできません。彼/彼女を引き抜くと、次に古いものを知らないからです。この病院の問題を解決するには、max heapを実装します。このヒープは、定義上、部分的に順序付けられています。つまり、患者を年齢で並べ替えることはできませんが、最も古い患者が常に一番上にいることはわかっているので、一定の時間で患者を引き出してO(1)、ログ時間でヒープのバランスを取り直すことができますO(log N)

より洗練された例:

整数のシーケンスがあり、medianを追跡したいとします。中央値は、配列された配列の中央にある数字です。

例:

[1, 2, 5, 7, 23, 27, 31]

上記の場合、7は中央値です。これは、より小さい数値を含む配列[1, 2, 5]は、大きい数字を含むものと同じサイズです[23, 27, 31]。通常、配列に偶数個の要素がある場合、中央値は中央の2つの要素の算術平均です(例:(5 + 7)/2

さて、中央値をどのように追跡しますか? 2つのヒープを持つことで、現在の中央値より小さい数値を含む1分のヒープと、現在の中央値より大きい数値を含む最大ヒープ。これで、これらのヒープのバランスが常に取れている場合、2つのヒープに同じ数の要素が含まれるか、1つの要素が他よりも多く、最も多くなります。

シーケンスに新しい要素を追加するときに、数値が現在の中央値よりも小さい場合は最小ヒープに追加し、そうでない場合は最大ヒープに追加します。現在、ヒープのバランスが取れていない場合(1つのヒープが他のヒープよりも1つ以上の要素を持っている場合)、pull最大のヒープからの要素とadd最小の要素になります。バランスが取れました。

41
André Pena

ヒープの特徴は、データが半順序に維持される構造であることです。したがって、完全な秩序を維持するコストとランダムなカオスを介して検索するコストとの間の良いトレードオフです。この特性は、選択、順序付け、分類など、多くのアルゴリズムで使用されます。

ヒープのもう1つの便利な特性は、配列からインプレースで作成できることです!

12
AticusFinch

選択アルゴリズムにも適しています(最小または最大を見つける)

3
Dan

一時リストをソートするときはいつでも、ヒープを考慮する必要があります。

3
Javier

最小要素と最大要素にそれぞれアクセスする場合は、最小ヒープまたは最大ヒープを使用できます。

0
QuadBiker