【C++】最小ヒープからk番目に小さい要素を求める方法
このチュートリアルでは、最小ヒープ(min-heap)からk番目に小さい要素を求めるプログラムをC++で作成します。
この問題は、優先度付きキュー(priority queue)を利用することで効率的に解くことができます。まずは、プログラムを完成させるまでの手順を確認していきましょう。
- 最小ヒープを正しい値で初期化します。
- 優先度付きキューを作成し、最小ヒープの根(ルート)ノードを挿入します。
- k − 1回繰り返すループを作成します。
- キューから最小の要素を取り出します(pop)。
- 取り出したノードの左の子と右の子を優先度付きキューに追加します。
- ループ終了後、優先度付きキューの先頭にある要素がk番目に小さい要素になっています。
- その値を返します。
アルゴリズムのポイント
この手法が正しく動作するのは、最小ヒープには「親ノードの値は必ず子ノード以下である」という性質が成り立つためです。各ノードの子だけを順次キューに追加していくことで、ヒープ全体をソートすることなく、小さい方から順にk個の要素だけを取り出すことができます。
計算量はO(k log k)となり、ヒープ全体を並べ替えてからk番目を求める方法(全体でO(n log n))よりも効率的です。
コード例
それでは、実際のコードを見てみましょう。
#include <bits/stdc++.h>
using namespace std;
struct Heap {
vector<int> elements;
int n;
Heap(int i = 0): n(i) {
elements = vector<int>(n);
}
};
inline int leftIndex(int i) {
return 2 * i + 1;
}
inline int rightIndex(int i) {
return 2 * i + 2;
}
int findKthSmallestElement(Heap &heap, int k) {
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> queue;
queue.push(make_pair(heap.elements[0], 0));
for (int i = 0; i < k - 1; ++i) {
int node = queue.top().second;
queue.pop();
int left = leftIndex(node), right = rightIndex(node);
if (left < heap.n) {
queue.push(make_pair(heap.elements[left], left));
}
if (right < heap.n) {
queue.push(make_pair(heap.elements[right], right));
}
}
return queue.top().first;
}
int main() {
Heap heap(10);
heap.elements = vector<int>{ 10, 14, 19, 24, 32, 41, 27, 44, 35, 33 };
cout << findKthSmallestElement(heap, 4) << endl;
return 0;
}実行結果
上記のコードを実行すると、次のような出力が得られます。
24
サンプルのヒープ {10, 14, 19, 24, 32, 41, 27, 44, 35, 33} を昇順に並べると「10 → 14 → 19 → 24 → …」となるため、4番目に小さい要素である「24」が出力されます。
まとめ
本チュートリアルでは、優先度付きキューを活用して、最小ヒープからk番目に小さい要素を効率的に取得する方法を学びました。ご不明な点がありましたら、コメント欄でお気軽にお知らせください。
-
C++で最大ヒープから最小値の要素を見つける方法
問題の概要最大ヒープ(max heap)の中から、最も小さい値を持つ要素を探す方法を解説します。以下のような最大ヒープを例に考えてみましょう。最大ヒープでは、親ノードの値は必ずその子ノードの値以上になります。この性質により、最小値は必ず葉ノード(leaf node)のいずれかに存在すると結論できます。ヒープが n 個のノードを含む場合、葉ノードの数は ceil(n/2) 個になります。また、最大ヒープは完全二分木であるため、配列として表現することができます。このとき、最初の葉ノードは floor(n/2) のインデックス以降に配置されます。上記の例では、最初の葉ノードはインデックス 5 に存在
-
C++でヒープソートを実装する方法:最小ヒープの完全ガイド
ヒープとはヒープ(Heap)とは、完全二分木のデータ構造であり、「最小ヒープ(Min Heap)」または「最大ヒープ(Max Heap)」のいずれかに分類されます。最大ヒープでは、ルートノードのキーがヒープ内のすべてのキーの中で最大値である必要があり、この性質は木の中のすべてのノードに対して再帰的に成り立たなければなりません。最小ヒープはその逆で、親ノードの値が常に子ノードの値以下になるという性質を持ちます。本記事では、最小ヒープを用いたヒープソートの実装方法を解説します。実装する関数の概要今回実装するクラスには、以下の主要なメンバ関数が含まれています。void BHeap::Insert(i