安定したヒープはありますか?


32

次の操作をサポートする優先度キューデータ構造はありますか?

  • Insert(x、p):優先度pで新しいレコードxを追加します
  • StableExtractMin():最小の優先度でレコードを返し、削除します。挿入順で関係を壊します。

したがって、Insert(a、1)、Insert(b、2)、Insert(c、1)、Insert(d、2)の後、StableExtractMinのシーケンスはa、c、b、dの順になります。

明らかに、ペアp t i m e を実際の優先度として保存することで、任意の優先度キューデータ構造を使用できますが、類推して、挿入時間(または挿入順序)を明示的に保存しないデータ構造に興味があります安定した選別に。(p,time)

同等(?):Ω(n)追加スペースを必要としないヒープソートの安定バージョンはありますか?


「a、c、b、d」という意味ですか?
ロススナイダー

レコードのリンクされたリストと、対応するリンクされたリストを指す優先順位をキーとするバランスの取れたバイナリツリーを持つヒープは機能しませんか?私は何が欠けていますか?
アルヤバタ

Moron:挿入順序を明示的に保存していますが、これはまさに避けたいことです。問題の説明を明確にしました(そしてRossのタイプミスを修正しました)。
ジェフ

回答:


16

Bently-Saxeメソッドは、かなり自然な安定した優先キューを提供します。

並べ替えられた配列シーケンスにデータを保存します。 A iのサイズは2 iです。各配列は、カウンターc iも保持します。配列エントリA i [ c i ] A i [ 2 i1 ]にはデータが含まれています。A0,,AkAi2iciA[c]A[21]

それぞれについて、のすべての要素A 私は最近になってのものより追加されたI + 1と各内のAのi個の要素が先に新しい要素の古い要素を配置することにより、破壊されるタイで値によって順序付けされています。これは、A iA i + 1をマージし、この順序を維持できることを意味することに注意してください。(マージ中に同順位の場合、A i + 1から要素を取得します。)AA+1AAA+1A+1

値挿入する、最小見つけるiは、その結果Aは、iがマージ、0要素を含む0... A I - 1及びXは、これを保存、A I及びセットC 0... cはIを適切に。バツAA0A1バツAc0c

最小値を抽出するには、A i [ c i ]の最初の要素がすべてのiで最小になり、c iを増分するような最大のインデックス見つけます。A[c]c

標準の引数により、これは操作ごとに償却時間を与え、上記の順序のために安定しています。Oログn

挿入と抽出のシーケンスでは、n 個の配列エントリ(空の配列を保持しない)とO log n ワードの簿記データを使用します。Mihaiのバージョンの質問には答えていませんが、安定した制約が多くのスペースオーバーヘッドを必要としないことを示しています。特に、必要な追加のスペースに下限Ω n ))がないことを示しています。nnOログnΩn

更新:ロルフFagerberg我々はヌル(非データ)の値を格納することができるかどうかということを指摘し、この全体のデータ構造はサイズの配列にパックすることができるN今まで挿入の数です。nn

最初に、をこの順序で配列にパックできることに注意してください(A kが最初で、空でない場合はA k 1が続きます)。この構造は、これまでに挿入された要素の数であるnのバイナリ表現によって完全にエンコードされます。nのバイナリ表現の位置iに1がある場合、A i2 iの配列位置を占有します。それ以外の場合、配列位置を占有しません。Ak,,A0AkAk1nniAi2i

ときに挿入し、、および1によって私達の配列の長さは、増加する、と私たちはマージすることができます0... A Iプラス、既存のインプレース安定マージアルゴリズムを使用して新しい要素。nA0,,Ai

ここで、null値を使用するのは、カウンターを取り除くことです。A は、我々は、続いて最初の値、保管C I残り続くヌル値、2つのI - C I - 1つの値を。extract-minの間、A 0 [ 0 ] A k [ 0 ]を調べることで、O log n 時間で抽出する値を見つけることができますA i [ 0でこの値を見つけるとciAici2ici1O(logn)A0[0],,Ak[0]我々はセット AをI [ 0 ]次に、NULLにして、上でバイナリ検索を行う A I最初の非ヌル値を見つけるために AをI [ C I ]及びスワップ A I [ 0 ] A I [ C I ]Ai[0]Ai[0]AiAi[ci]Ai[0]Ai[ci]

最終結果:構造全体は、挿入ごとに長さが増加する1つの配列と、挿入数をカウントする1つのカウンターで実装できます。n


1
これは、O(n)抽出後の特定の瞬間に潜在的にO(n)の余分なスペースを使用しますか?この時点で、あなたにも...あまりにも優先順位を保存するかもしれない
Mehrdad

10

あなたの制約が何なのか分かりません。以下は資格がありますか?データを配列に格納します。これは暗黙的なバイナリツリー(バイナリヒープなど)として解釈されますが、データ項目は内部ノードではなくツリーの最下位レベルにあります。ツリーの各内部ノードには、2つの子からコピーされた値のうち小さい方が格納されます。同点の場合は、左の子をコピーします。

最小値を見つけるには、ツリーのルートを見てください。

要素を削除するには、削除済みとしてマークし(遅延削除)、ツリーを上に伝搬します(削除された要素のコピーを保持したルートへのパス上の各ノードは、他の子のコピーで置き換えられる必要があります)。削除された要素の数を維持し、すべての要素の一部が大きくなりすぎた場合、最下位レベルの要素の順序を維持しながら構造を再構築します。再構築は線形時間を要するため、この部分は操作の複雑さ。

要素を挿入するには、ツリーの一番下の行の次の空き位置に要素を追加し、ルートへのパスを更新します。または、一番下の行がいっぱいになった場合、ツリーのサイズを2倍にします(再び償却引数を使用します。この部分は、標準のバイナリヒープがその配列を超えたときに再構築する必要があることに注意してください)。

ただし、Mihaiのより厳密なバージョンの質問に対する答えではありません。なぜなら、削除を遅延処理するスペースコストを無視しても、実際の暗黙的なデータ構造の2倍のメモリを使用するからです。


私はこれが好き。通常の暗黙的なツリーの最小ヒープの場合と同様に、キャッシュ効果のために、おそらく3項または4項の暗黙的なツリーの方が高速になります(さらに比較が必要な場合でも)。
ジョナサングレール

8

次はあなたの問題の有効な解釈ですか:

補助情報なしでA [1..N]の配列にNキーを保存する必要があります。* insert key * delete min。複数の最小値がある場合、最も早い挿入要素を選択します

ほとんどの暗黙的なデータ構造が、一部の要素のローカル順序付けでビットをエンコードするトリックを演じていることを考えると、これは非常に難しいように見えます。ここで複数の人が等しい場合、彼らの順序は保持されなければならないので、そのようなトリックは不可能です。

面白い。


1
元の質問には実際には答えないので、これは答えではなくコメントであるべきだと思います。(削除してコメントとして追加できます。)
ユッカスオメラ

5
ええ、このウェブサイトは少しばかげています。私たちには評判、ボーナス、報酬、コメントするためのあらゆる種類の方法がありますが、私にはわかりません。私はこれが子供向けのゲームのように見えることを望みます。
ミハイ

1
彼はコメントを投稿するためにもっと担当者が必要だと思います。それが問題です。
スレシュヴェンカト

@シュレシュ:ああ、そうだね、覚えてなかった。この種の状況を実際にどのように処理する必要がありますか(つまり、新しいユーザーが質問に答える前に説明を求める必要がありますか)。
ユッカスオメラ

2
簡単な解決法はない。私はこれをMOでよく見ました。Mihaiの場合、Mihaiが担当者を獲得するのに問題はありません:)
Suresh Venkat

4

短い答え:できません。

少し長い答え:

エントリの「年齢」を保存するために追加スペースが必要になります。これにより、同一の優先順位を区別できます。また、高速な挿入と取得を可能にする情報のためにΩ n スペースが必要です。さらにペイロード(値と優先度)。Ω(n)Ω(n)

また、保存するペイロードごとに、アドレス内の一部の情報を「隠す」ことができます(たとえばはYがXより古いことを意味します)。しかし、その「隠された」情報では、「年齢」または「高速検索」情報を非表示にします。両方ではありません。addr(X)<addr(Y)


不正確な不安定な擬似数学で非常に長い答え:

注:前述のとおり、2番目のパートの最後は大ざっぱです。数学者がより良いバージョンを提供できるなら、私は感謝するでしょう。

Xビットマシン(32ビットまたは64ビットなど)に関係するデータの量について考えてみましょう。レコード(値と優先度)はマシンワード幅です。P

:あなたは、部分的に順序付けられている可能性のあるレコードのセット持っている及び1 = 1 がありますが、比較することはできません1 B 1 (a,1)<(a,2)(a,1)=(a,1)(a,1)(b,1)

ただし、レコードのセットの2つの比較できない値を、それらが挿入された時期に基づいて比較できるようにしたい場合があります。したがって、ここには別の値のセットがあります:挿入された値、および半順序でそれを拡張したい場合:XYの前に挿入された場合。バツ<YバツY

最悪のシナリオでは、メモリはフォームのレコード(各?で異なるでいっぱいになるので、どちらを挿入するかを決定するには、挿入時間に完全に依存する必要があります。最初に。1

  • 挿入時間(まだ構造内にある他のレコードと比較して)には、ビットの情報が必要です(Pバイトペイロードと2 Xアクセス可能なメモリバイト)。バツlog2P2バツ
  • ペイロード(レコードの値と優先度)には、マシンワードの情報が必要です。P

つまり、保存するレコードごとに、何らかの方法で追加ビット情報を保存する必要があります。そして、それはnレコードのO n です。バツlog2POnn

さて、各メモリ「セル」が提供する情報のビット数はどれくらいですか?

  • ビットのデータ( Wはマシンワード幅)。WW
  • ビットのアドレス。X

さて、聞かせてのは、前提と(ペイロードが広い(通常は1つのオクテット少なくとも1つの機械語です))。これは、X l o g 2P < Xであることを意味するため、セルのアドレスに挿入順序情報を収めることができます。それがスタックで起こっていることです。最も低いアドレスのセルが最初にスタックに入りました(そして最後に出ます)。P1Xlog2(P)<X

したがって、すべての情報を保存するには、2つの可能性があります。

  • 挿入順序をアドレスに保存し、ペイロードをメモリに保存します。
  • 両方をメモリに保存し、他の用途のためにアドレスを空けておきます。

明らかに、無駄を避けるために、最初のソリューションを使用します。


次に、操作について説明します。あなたが持っていることを望むと思う:

  • Insert(task,priority)O(logn)
  • StableExtractMin()O(logn)

StableExtractMin()

本当に本当に一般的なアルゴリズムは次のようになります。

  1. O(logn)
  2. O(logn)
  3. それを返します。

0(1)O(1)O(1)

O(logn)2(Xlog2(P))

Xlog2(P)O(logn)O(logn)

O(logn) on average to get to the min).

Now, when deleting that element, we'll need to augment the next min record so it has the right amount of information to allow O(logn) retrieval next time, that is, so it has Xlog2(P) bits of information discriminating it from the other candidates.

That is, if it doesn't have already enough information, you'll need to add some. In a (non-balanced) binary search tree, the information is already there : You'll have to put a NULL pointer somewhere to delete the element, and without any further operation, the BST is searchable in O(logn) time on average.

After this point, it's slightly sketchy, I'm not sure about how to formulate that. But I have the strong feeling that each of the remaining elements in your set will need to have Xlog2(P) bits of information that will help find the next min and augment it with enough information so that it can be found in O(logn) time next time.

The insertion algorithm usually just needs to update part of this information, I don't think it will cost more (memory-wise) to have it perform fast.


Now, that means that we'll need to store Xlog2(P) more bits of information for each element. So, for each element, we have :

  • The insertion time, Xlog2(P) bits.
  • The payload P machine words.
  • The "fast search" information, Xlog2(P) bits.

Since we already use the memory contents to store the payload, and the address to store the insertion time, we don't have any room left to store the "fast search" information. So we'll have to allocate some extra space for each element, and so "waste" Ω(n) 余分なスペース。


あなたは本当にあなたの答えをCWにするつもりでしたか?
Suresh Venkat

はい。私の答えは、中に述べられているように、100%正確ではありません、そして、私がもうSOまたは何でもない場合でも誰かがそれを修正できれば良いでしょう。知識は共有されるべきであり、知識は変更可能であるべきです。しかし、多分私はCWの使用法を誤解していたでしょう、もしそうなら、教えてください:)。編集:おっと、確かに、CWの投稿から担当者を取得できないことと、コンテンツがCC-wikiのライセンスを受けていることを発見しました...残念です:)。
スザンヌデュペロン

3

優先度キューをバランスの取れたバイナリツリーとして実装する場合(一般的な選択肢)、ツリーに要素を追加するときに、同じ優先度の要素の左側に挿入されることを確認する必要があります。
このようにして、挿入順序はツリー自体の構造にエンコードされます。


1
しかし、これによりポインターにO(n)スペースが追加されます。質問者はこれを避けたいと思いますか?
ジェレミー

-1

I don't think that's possible

コンクリートケース:

       x
    x    x
  x  x  1  x
1  x  

min heap with all x > 1

ヒープ化は最終的にそのような選択肢を与えます

       x
    1    1
  x  x  x  x
x  x  

今、どの1をルートに伝播しますか?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.