バイナリ最小ヒープのキーの増加とキーの減少


16

バイナリヒープの多くの議論では、通常、min-heapでサポートされている操作として減少キーのみがリストされています。たとえば、CLR 6.1章およびこのウィキペディアのページ。通常、min-heapのキーが増加しないのはなぜですか?増加した要素(x)を最小の子と繰り返し交換することにより、O(height)で、子がxより大きくなるまでそれを行うことができると思います。

例えば

IncreaseKey(int pos, int newValue)
{
   heap[pos] = newValue;
   while(left(pos) < heap.Length)
   {
      int smallest = left(pos);
      if(heap[right(pos)] < heap[left(pos)])
         smallest = right(pos);
      if(heap[pos] < heap[smallest])
      { 
         swap(smallest, pos);
         pos= smallest;
      }
      else return;
   }   
}

上記は正しいですか?そうでない場合、なぜですか?はいの場合、min-heapのキーがリストされないのはなぜですか?


1
すべての答えを読んだ後、おそらく奇妙な省略であり、おそらくダイクストラアルゴリズムでmin-heapが歴史的に初めて使用されたことが原因です。
maaartinus 14

3
もちろん、削除の後に挿入を使用して増加キーを常に実装できます。削除自体は、減少キー(-∞へ)の後に削除minとして実装できます。
-davmac

@maaartinusコメントが正しい答えです。
最大

回答:


6

提案するアルゴリズムは単純にヒープ化です。実際、最小ヒープ内の要素の値を増やしてから、そのサブツリーをヒープ化すると、正当な最小ヒープになります。


それでは、なぜCLRまたはWikipediaのリストがキーを増やしてサポートされる操作にならないのですか?ちょっとしたヒープでは不可能だと思うのはちょっと誤解されました
-GatotPujo

誤解を招くことに同意しますが、アルゴリズムに間違いはありません。
シャール

5

操作がリストされていない理由は、特定のデータ構造を使用して簡単に実装できるすべての操作ではなく、他の方法に関心があるためです。一連の操作を考えると、これらの操作を実装する最も効率的な方法は(スペースと時間の点で)何ですか。(ただし、これについては後で追加します)

バイナリヒープは抽象データ構造の優先度キューを実装し、is_empty、add_element(優先度を持つキー)、find_min、delete_minの操作を要求します。より高度なキューを使用すると、キーの優先度を(min_heapで)下げることも、さらに上げることもできます。実際、あなたは実装を与えました。

2つの発言。操作は、配列からヒープを効率的に構築するheapify関数で使用されます。heapifyでは、操作が繰り返されます(最後のキーから開始)。

次に、最も重要なこととして、コードはノードの位置を使用します。不正な純粋なデータ構造の優先度キューの場合。そのデータ構造は、キーを指定して特定の操作を実行するように要求します。そのため、要素の優先度を下げたり上げたりするためには、まずその要素を見つける必要があります。それがリストされていない主な理由だと思います。


1
説明してくれてありがとう。ただし、CLR減少キーでは、パラメーターとしてノードとしての位置もあります。
GatotPujo

あなたが正しいです。CLRSのセクション6.5の優先度キューの定義で、この非対称性の理由を見つけることができませんでした。この章のアプリケーションであるHeapsortでは、increase-keyは使用されていません。増加と減少の非対称性は、たとえばダイクストラのアルゴリズムでデータ構造が使用される方法にのみ関係しているようです。そこで(最小ヒープを使用して)選択されたノードのいくつかはより緊急になり、ヒープ内で「上」に移動します。
ヘンドリック

0

最初に考慮すべきことは、サポートされている操作とは何かだと思いますか?

「特定の固定キーを使用して値を挿入する」(整数領域から取得したキー、キー= 3で挿入するなど)は、最小ヒープでサポートされる操作に対応していますか?

いいえ、その操作はより一般的なサポートされている操作で簡単に実装できるためです。同様に、既存のinsert操作を使用して2つの要素を一度に挿入できます。

一方、insert実装の詳細を公開する以外の方法で操作を定義することはできません。ウィキペディアのページにリストされている操作についてはほとんど同じですが、heapify例外として、おそらくのシーケンスで実装できinsertます。

言い換えると、タイプに提供される基本的な操作があり、それらがうまく機能するための実装の詳細に密接に結びついており、他の操作もあります。正規のものの。

その定義を念頭に置いて、パフォーマンスを損なうことなく、増加キーを他のサポートされている操作で排他的に実装できると思いますか?その場合、それは上記の定義でサポートされている操作ではありません。そうでない場合は、正しいかもしれません。

おそらく、私が提供するサポートされている操作の定義は、私の知る限り私のものです。それは正式ではないので、議論の対象となります(ただし、私にはかなり明確に思えます)。ただし、サポートされている操作がデータ型に対して何であるかを明確かつ明確に定義するソースを提供できるか、少なくとも私のものよりも良い用語で定義できるソースを提供できればうれしいです(その定義はCLRで与えられますか?私はコピーを持っていません)。

2番目のポイントは、優先度キュー(バイナリヒープの存在理由)を定義する方法です。でincrease_key、その適切な使用のためにそのデータ型のために必要な操作、すなわち?

ご覧のとおり、私の角度はすべて定義に関するものです。私はあなたの質問に対する答えを実際に提供するのではなく、いくつかのポインタを提供するだけなので、機能強化は大歓迎です。


1
サンプルの使用例は、最近使用したものに基づいてオブジェクトの優先度キューを維持する場合です(たとえば、最近使用したオブジェクトを簡単に削除できるようにするため)。最終アクセス日をキーとして最小ヒープを使用できます。オブジェクトにアクセスする場合、そのキーを増やす必要があります。
GatotPujo

非常に良い点。私の見方は少し限られているようです。本当に、@ HendrikJanの答えは非常に良い説明をもたらします。
ディディエック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.