【C++】要素を挿入するたびにK番目に小さい要素を求める方法
はじめに
このチュートリアルでは、要素を挿入するたびにK番目に小さい要素を求めるアルゴリズムを解説します。
この問題は、最小ヒープ(min-heap)を利用することで効率よく解決できます。それでは、プログラムを完成させるための手順を順番に見ていきましょう。
アルゴリズムの手順
- ランダムなデータで配列を初期化します。
- 優先度付きキュー(priority queue)を初期化します。
- 最初の k - 1 個の段階では、まだ K 番目に小さい要素が存在しないため、「- 」のような任意の記号を出力しておきます。
- k 番目から n 番目まで繰り返すループを作成します。
- 最小ヒープのルート(先頭要素)を出力します。
- 新しい要素がヒープのルートより大きい場合は、ルートを取り出し(pop)、代わりにその要素を挿入(push)します。
C++ では、priority_queue の第3テンプレート引数に greater<int> を指定することで、最も小さい値が常に先頭に来る最小ヒープとして扱えるようになります。
サンプルコード
それでは、実際のコードを見てみましょう。
#include <bits/stdc++.h>
using namespace std;
void findKthSmallestElement(int elements[], int n, int k) {
priority_queue<int, vector<int>, greater<int>> queue;
for (int i= 0; i < k - 1; i++) {
queue.push(elements[i]);
cout << "- ";
}
queue.push(elements[k-1]);
for (int i = k; i < n; i++) {
cout << queue.top() << " ";
if (elements[i] > queue.top()) {
queue.pop();
queue.push(elements[i]);
}
}
cout << queue.top() << endl;
}
int main() {
int arr[] = {3, 5, 6, 2, 7, 8, 2, 3, 5, 9};
findKthSmallestElement(arr, 10, 5);
return 0;
}
実行結果
上記のコードを実行すると、次のような出力が得られます。
- - - - 2 3 3 3 5 5
計算量
このアルゴリズムでは、各要素ごとにヒープへの挿入・削除を行います。ヒープのサイズは最大でも k であるため、全体の時間計算量は O(n log k)、必要なメモリ領域は O(k) となります。全要素を毎回ソートし直す方法(O(n² log n))と比べて非常に効率的です。
まとめ
今回は、最小ヒープ(優先度付きキュー)を使って、挿入のたびに K 番目に小さい要素を求める方法を紹介しました。このチュートリアルについて質問がある場合は、コメント欄でお気軽にお知らせください。
-
C++で配列内の各要素より大きい最も近い値を検索する方法
この記事では、配列内の各要素に対して「それより大きい値のうち最も近い値」を求める方法を解説します。ある要素 x より大きな値が配列内に存在する場合、その中で最小のものが答えとなります。存在しない場合は -1 を返します。 例として、配列が [10, 5, 11, 6, 20, 12] の場合、結果は [11, 6, 12, 10, -1, 20] になります。20 より大きな値は配列内に存在しないため、-1 を出力します。 解決アプローチ この問題は、C++ STL の set を使うことで効率的に解けます。set は平衡二分探索木を基に実装されており、常に要素をソートされた状態で保持します。
-
配列の分割(パーティション)手法でk番目に小さい要素を見つけるC++プログラム
本記事では、配列を分割(パーティション)する手法を用いて、配列内のk番目に小さい要素を求めるC++プログラムを解説します。この手法はクイックソートの考え方を応用したもので、配列全体をソートすることなく、目的の要素だけを効率的に特定できる点が特徴です。 アルゴリズム まず、ピボットを基準に配列を分割する CreatePartition() 関数と、その結果をもとにk番目に小さい要素が存在する範囲を再帰的に絞り込む Partition() 関数を使用します。 Begin 関数 CreatePartition() は 配列 a、下限 l、上限 h を引数にとる in := l、pi