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

C++でソート済みのpair型vectorに対して二分探索を行う方法

C++では、std::pair を格納したソート済みの std::vector に対しても、標準ライブラリの binary_search 関数を使って二分探索(バイナリサーチ)を実行できます。ただし、pair のどの要素(first / second)をキーとして比較するかをコンパイラに伝える必要があるため、カスタム比較ファンクタを定義するのがポイントです。

アルゴリズム

処理の流れは以下の通りです。

開始
  keycompare 構造体を宣言する
    operator()(const pair& v, const int& k) を定義し、bool を返す
      status = v.first < k
      status を返す
    operator()(const int& k, const pair& v) を定義し、bool を返す
      status = k < v.first
      status を返す
  vector v を宣言する
  v 内に int 型のキーと値のペアを宣言する
  push_back() 関数で v に値を挿入する
  sort() 関数で v の全要素をソートする
  「Sorted vector」を出力する
  「KEY」「VALUE」を出力する
  for ループで各要素 n の first と second を出力する
  binary_search(v.begin(), v.end(), 50, keycompare()) が真なら
    「50 exists in vector」を出力する
  偽なら
    「50 does not exist」を出力する
  binary_search(v.begin(), v.end(), 7, keycompare()) が真なら
    「7 exists in vector」を出力する
  偽なら
    「7 does not exist」を出力する
終了

ポイント:比較ファンクタ keycompare の役割

binary_search は通常 < 演算子で要素同士を比較しますが、pair 型の vector に対して単純な整数値を渡すと型が一致せず、そのままでは使えません。そこで keycompare 構造体のように、operator() を「(pair, 整数)」と「(整数, pair)」の2パターンでオーバーロードしたファンクタを第4引数として渡すことで、pair の first 要素(キー)を基準とした双方向の比較が可能になります。

サンプルコード

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

struct keycompare {
    bool operator()(const pair<int, int>& v, const int& k) {
        return (v.first < k);
    }
    bool operator()(const int& k, const pair<int, int>& v) {
        return (k < v.first);
    }
};

int main() {
    vector<pair<int, int>> v;
    v.push_back(make_pair(7, 26));
    v.push_back(make_pair(6, 76));
    v.push_back(make_pair(4, 16));
    v.push_back(make_pair(5, 36));

    // ベクトルをキー順にソート
    sort(v.begin(), v.end());

    cout << "Sorted vector" << endl;
    cout << "KEY" << '\t' << "VALUE" << endl;
    for (auto& n : v)
        cout << n.first << '\t' << n.second << endl;

    if (binary_search(v.begin(), v.end(), 50, keycompare()))
        cout << "50 exists in vector";
    else
        cout << "50 does not exist";
    cout << endl;

    if (binary_search(v.begin(), v.end(), 7, keycompare()))
        cout << "7 exists in vector";
    else
        cout << "7 does not exist";

    return 0;
}

実行結果

Sorted vector
KEY     VALUE
4       16
5       36
6       76
7       26
50 does not exist
7 exists in vector

まとめ

pair 型の vector に対して二分探索を行う場合は、キーとなる要素(本例では first)に基づいて双方向の比較ができるファンクタを用意することが重要です。二分探索の計算量は O(log n) であり、先頭から順に調べる線形探索 O(n) と比べて、大量のデータでも高速に要素の存在を判定できます。

  1. C++で二分木を二分探索木(BST)へ変換する方法を解説

    二分木(Binary Tree)とは二分木とは、木構造の各ノードが最大で2つの子ノードを持つことができる特別な木構造です。これらの子ノードは、それぞれ「左の子ノード」と「右の子ノード」と呼ばれます。シンプルな二分木の例は以下の通りです。二分探索木(BST)とは二分探索木(BST)は、以下のルールに従う特別な木構造です。左の子ノードの値は、常に親ノードの値より小さい右の子ノードの値は、常に親ノードの値より大きいすべてのノードが、それぞれ独立して二分探索木の性質を満たす二分探索木(BST)の例は以下の通りです。二分探索木は、検索や最小値・最大値の探索といった操作の計算量を削減するために用いられるデ

  2. C++プログラムにおける二分探索(バイナリサーチ)の基本と実装

    二分探索(バイナリサーチ)とは二分探索は「半区間探索」「対数探索」「バイナリチョップ」とも呼ばれる検索アルゴリズムで、ソート済みの配列の中から目的の値が存在する位置を効率的に見つけ出します。基本的な仕組みは非常にシンプルです。まず、探したい値(ターゲット値)を配列の中央の要素と比較します。一致しなかった場合は、ターゲット値が存在し得ない半分を丸ごと排除し、残りの半分に対して同様の比較を繰り返します。この「中央との比較」と「範囲の絞り込み」を続け、ターゲット値が見つかるか、検索範囲が空になる(=配列にその値が存在しない)かのどちらかで処理が終了します。アイデア自体は簡単ですが、正しく実装するには