C++ STLのlower_boundとupper_boundでソート済み配列のfloor・ceilを効率的に求める方法
この記事では、C++ の標準テンプレートライブラリ(STL)を活用して、ソート済み配列内の指定した値に対する「floor(床)」と「ceil(天井)」を求めるプログラムを解説します。
floorとceilとは?
まず用語を整理しましょう。
- floor(床):配列内に存在する、対象の値以下の最大の要素
- ceil(天井):配列内に存在する、対象の値以上の最小の要素
例えば、配列 {1, 2, 4, 7, 11} において値「5」の floor は「4」、ceil は「7」となります。
STLのlower_bound()とupper_bound()を使う
ソート済み配列に対しては、STLが提供する二分探索系の関数が非常に有効です。計算量は O(log n) に抑えられるため、線形探索よりも高速です。
lower_bound():指定した値「以上」になる最初のイテレータを返す → floor の計算に利用upper_bound():指定した値「より大きい」最初のイテレータを返す → ceil の計算に利用
サンプルコード
#include <bits/stdc++.h>
using namespace std;
// 指定された値のfloorを求めて出力
void printFloor(int arr[], int n1,
int findFloor[], int n2){
int low;
cout << "Floor : ";
for (int i = 0; i < n2; i++) {
low = (lower_bound(arr, arr + n1, findFloor[i]) - arr);
if (arr[low] > findFloor[i])
cout << arr[low - 1] << " ";
else
cout << arr[low] << " ";
}
cout << endl;
}
// 指定された値のceilを求めて出力
void printCeil(int arr[], int n1,
int findCeil[], int n2){
int up;
cout << "Ceil : ";
for (int i = 0; i < n2; i++) {
up = (upper_bound(arr, arr + n1, findCeil[i]) - arr);
if (arr[up] > findCeil[i] && arr[up - 1] == findCeil[i]) {
cout << arr[up - 1] << " ";
}
else
cout << arr[up] << " ";
}
cout << endl;
}
int main(){
int arr[] = { 1, 2, 4, 7, 11, 12, 23, 30, 32 };
int n1 = sizeof(arr) / sizeof(arr[0]);
cout << "Original Array: ";
for (unsigned int i = 0; i < n1; i++)
cout << " " << arr[i];
cout << "\n";
int find[] = { 1, 3, 5, 7, 20, 24 };
int n2 = sizeof(find) / sizeof(find[0]);
cout << "Values: ";
for (unsigned int i = 0; i < n2; i++)
cout << find[i] << " ";
cout << "\n";
printFloor(arr, n1, find, n2);
printCeil(arr, n1, find, n2);
return 0;
}
実行結果
Original Array: 1 2 4 7 11 12 23 30 32 Values: 1 3 5 7 20 24 Floor : 1 2 4 7 12 23 Ceil : 1 4 7 7 23 30
コードのポイント解説
printFloor関数の仕組み
lower_bound() が返す位置の要素が検索値より大きい場合、その直前の要素が floor になります。逆に、返された位置の要素が検索値と等しい場合は、その要素自体が floor です。
printCeil関数の仕組み
upper_bound() は検索値より大きい最初の要素を指すため、重複要素の扱いに注意が必要です。直前の要素が検索値と一致している場合(つまり配列内に検索値が存在する場合)は、その値自体が ceil となります。
注意点
この実装では、検索値が配列の最小値より小さい、または最大値より大きい境界ケースは考慮されていません。実務で使用する際は、low や up が配列の範囲外にならないよう、インデックスの範囲チェックを追加することをおすすめします。
まとめ
C++ STL の lower_bound() と upper_bound() を使えば、ソート済み配列から floor と ceil を O(log n) の計算量で効率的に求められます。二分探索を自分で実装する必要がないため、コードも簡潔になり、バグも減らせます。ソート済みデータの検索処理では、ぜひ活用してみてください。
-
C++でSTLを使って配列の積を求める方法
C++では、STL(標準テンプレートライブラリ)のaccumulate関数を利用することで、配列内のすべての要素の積を簡潔に求めることができます。ここでは、その具体的な実装例を紹介します。 アルゴリズム 開始 配列の各要素の値を初期化する。 ユーザー定義関数 accumulate を呼び出し、配列全体の積を取得する。 計算結果を出力する。 終了 サンプルコード #include <iostream> #include <numeric> using namespace std; int ProductOfArray(int p[], int n)
-
C++のceil関数とfloor関数の使い方をわかりやすく解説
ceil関数とは ceil関数は、引数に渡した値以上となる整数のうち、最も小さい値(切り上げた値)を返す関数です。C++では「cmath」ヘッダーファイル内で宣言されており、引数には天井値を求めたい単一の値を指定します。なお、引数のデータ型はdouble型・float型・long double型のいずれかである必要があります。 C++におけるceil関数の構文は以下のとおりです。 double ceil(double x); float ceil(float x); それでは、ceil関数を使用した具体的なサンプルコードを見ていきましょう。 サンプルコード #include <iost