最小ヒープの配列実装で x より小さいすべてのキーを見つけるアルゴリズムを説明できる人がいますか? 実行時間を少なくとも O(k) にしたいと考えています。ここで、k は報告されたキーの数です。
私はこれでしばらく頭を悩ませてきました。
最小ヒープの配列実装で x より小さいすべてのキーを見つけるアルゴリズムを説明できる人がいますか? 実行時間を少なくとも O(k) にしたいと考えています。ここで、k は報告されたキーの数です。
私はこれでしばらく頭を悩ませてきました。
「少なくとも」の実行時間を取得することはそれほど難しいことではありません、私はあなたが「せいぜい」を意味すると思います。
残念ながら、最小ヒープは最小値以外のものを見つけるのにあまり適していません。
ヒープのツリービューの幅優先探索を実行し、 Xに到達したすべてのブランチを終了できます。これはO(k)になりますが、複雑になります。
Y <= XであるすべてのYを見つけるには、配列全体をスキャンすることもできます。これはO(n)になりますが、オーバーヘッドははるかに少なくなります。
選択は比率n/kに依存します
ツリー最小ヒープの単純な再帰アルゴリズムがあります。
void smaller_than(Node *node, int x)
{
if (node->value >= x)
{
/* Skip this node and its descendants, as they are all >= x . */
return;
}
printf("%d\n", node->value);
if (node->left != NULL)
smaller_than(node->left, x);
if (node->right != NULL)
smaller_than(node->right, x);
}
サブツリーのルートが x 以上の値を持つ場合、最小ヒープの定義により、そのすべての子孫も x 以上の値を持つことになります。アルゴリズムは、通過するアイテムよりも深く探索する必要がないため、O(k) です。
もちろん、これを配列アルゴリズムに変換するのは簡単なことです。
#define ROOT 0
#define LEFT(pos) ((pos)*2 + 1)
#define RIGHT(pos) ((pos)*2 + 2)
void smaller_than(int x, int pos, int heap[], int count)
{
/* Make sure item exists */
if (pos >= count)
return;
if (heap[pos] >= x)
{
/* Skip this node and its descendants, as they are all >= x . */
return;
}
printf("%d\n", heap[pos]);
smaller_than(x, LEFT(pos), heap, count);
smaller_than(x, RIGHT(pos), heap, count);
}
配列としての実装は無関係です。トップダウンのツリー検索を実行できます。「従来の」ポインターを使用する代わりに、それぞれの子ノードのインデックスを計算する必要があります。
邪魔にならないように、上から再帰検索を行い、現在のノードが x より大きい各ブランチで再帰を停止します。これにより、一般に、チェックする必要のない多くの値が削除されます。
k 戻り値を使用すると、 O(k) が明らかに最良のケースです。最上位ノードが <= x の場合、すぐに結果を取得し始めます。大きい場合は完了です - 結果は空です。
そこから、値 > x の分岐に到達するまで、サブツリーをずっと下って結果が得られます。これらの枝を剪定するには、最大で 2*k チェックを実行する必要があるため、合計で O(k) のように見えます。