プログラミング
 Computer >> コンピューター >  >> プログラミング >> プログラミング

ランダム化メルダブルヒープ(メルダブル優先キュー)の基本操作を徹底解説

ランダム化メルダブルヒープ(Randomized Meldable Heap、別名:メルダブル優先キュー)は、挿入・削除・探索といった一般的な操作を多数サポートするデータ構造です。具体的には「挿入(Insert)」「削除(Remove)」、そして最小値を取得する「findMin」が代表的な操作として知られています。さらに、挿入と削除の操作は、メルダブルヒープ固有の追加操作である Meld(A1, A2) を基盤として実装されています。

Meld(マージ)

meld(merge、統合とも呼ばれます)操作の基本的な目的は、2つのヒープA1とA2(それぞれのルートノードを受け取る)を統合し、結果として単一のヒープノードを返すことです。このノードは、A1とA2を根とする2つの部分木に含まれるすべての要素を持つヒープのルートノードとなります。

このmeld操作の優れた特徴は、再帰的に定義できる点です。どちらかのヒープがnull値に関連付けられている場合、マージは空集合との結合として完了し、空でない方のヒープのルートノードがそのまま返されます。A1とA2の両方がnilでない場合は、A1 > A2 であるかどうかを確認し、真であれば2つを入れ替えます。これにより A1 < A2 が保証され、統合後のヒープのルートノードには必ずA1が含まれることになります。続いて、A2とA1.leftまたはA1.rightを再帰的にマージします。ここで登場するのが乱択化(ランダム化)です。どちら側の子とマージするかという判断は、コイントスによって決められるためです。

function Meld(Node A1, Node A2)
if A1 is nil => return A2
if A2 is nil => return A1
if A1 > A2 => swap A1 and A2
if coin_toss is 0 => A1.left = Meld(A1.left, A2)
else A1.right = Meld(A1.right, A2)
return A1

Insert(挿入)

meld操作さえ実装されてしまえば、メルダブルヒープへの挿入は非常にシンプルです。まず、値pを格納した新しいノードaを作成します。その後、この新しいノードをヒープのルートノードとマージするだけで完了です。

function Insert(p)
Node a = new Node
a.p = p
root = Meld(a, root)
root.parent = nil
increment node count

Remove(削除)

挿入操作と同じくらい簡単で、Remove()もmeld操作を利用して、ヒープからルートノードを取り除きます。これは、ルートノードの2つの子ノード同士をマージし、返されたノードを新しいルートとすることで実現されます。

function Remove()
rootNode = Meld(rootNode.left, rootNode.right)
if rootNode is not nil => rootNode.parent = nil
decrement node count

FindMin(最小値の取得)

おそらくランダム化メルダブルヒープの中で最も単純な操作がFindMin()です。ヒープのルートノードに現在格納されている要素をそのまま返すだけで、最小値を取得できます。

その他の追加操作

メルダブルヒープには、上記以外にも最悪計算量でO(log n)の効率を保てる便利な操作が用意されています。

  • Remove(a) - 指定されたノードaとそのキーをヒープから削除します。
  • Absorb(P) - 別のメルダブルヒープPのすべての要素をこのヒープに移し、その過程でPを空にします。
  • DecreaseKey(a, q) - ノードa内のキーをqへ減少させます(前提条件:q <= a.p)。
  1. C++ STL(標準テンプレートライブラリ)のプライオリティキュー徹底解説

    プライオリティキュー(優先度付きキュー)は、優先度を持つ要素のコレクションを格納するための抽象データ型(ADT)です。各要素は優先度に基づいて挿入・削除が行われ、最も優先度の高い要素はいつでも取り出すことができます。スタックやキュー、リストなどの線形データ構造とは異なり、プライオリティキューは要素を格納位置の順序ではなく、優先度に基づいて管理する点が大きな特徴です。C++では、STLの <queue> ヘッダで提供されており、デフォルトでは最大値が先頭に来る構造になっています。プライオリティキューがサポートする主な操作size() — プライオリティキュー内の要素数を返し、サイズを

  2. C++で双方向リンクリストを使用した優先度付きキューの実装

    整数値のデータと優先度が与えられ、その優先度に従って双方向リンクリスト(doubly linked list)を作成し、結果を表示することが本記事の課題です。 優先度付きキューとは? キュー(Queue)はFIFO(First In, First Out:先入れ先出し)方式のデータ構造であり、最初に挿入された要素が最初に取り出されます。優先度付きキュー(Priority Queue)は、要素の優先度に応じて挿入や削除を行えるキューの一種です。キュー、スタック、リンクリストなどのデータ構造を使って実装でき、本記事では双方向リンクリストを用います。 優先度付きキューは、次のルールに従って動作しま