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

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 となります。

注意点

この実装では、検索値が配列の最小値より小さい、または最大値より大きい境界ケースは考慮されていません。実務で使用する際は、lowup が配列の範囲外にならないよう、インデックスの範囲チェックを追加することをおすすめします。

まとめ

C++ STL の lower_bound()upper_bound() を使えば、ソート済み配列から floor と ceil を O(log n) の計算量で効率的に求められます。二分探索を自分で実装する必要がないため、コードも簡潔になり、バグも減らせます。ソート済みデータの検索処理では、ぜひ活用してみてください。

  1. C++でSTLを使って配列の積を求める方法

    C++では、STL(標準テンプレートライブラリ)のaccumulate関数を利用することで、配列内のすべての要素の積を簡潔に求めることができます。ここでは、その具体的な実装例を紹介します。 アルゴリズム 開始 配列の各要素の値を初期化する。 ユーザー定義関数 accumulate を呼び出し、配列全体の積を取得する。 計算結果を出力する。 終了 サンプルコード #include <iostream> #include <numeric> using namespace std; int ProductOfArray(int p[], int n)

  2. C++のceil関数とfloor関数の使い方をわかりやすく解説

    ceil関数とは ceil関数は、引数に渡した値以上となる整数のうち、最も小さい値(切り上げた値)を返す関数です。C++では「cmath」ヘッダーファイル内で宣言されており、引数には天井値を求めたい単一の値を指定します。なお、引数のデータ型はdouble型・float型・long double型のいずれかである必要があります。 C++におけるceil関数の構文は以下のとおりです。 double ceil(double x); float ceil(float x); それでは、ceil関数を使用した具体的なサンプルコードを見ていきましょう。 サンプルコード #include <iost