C ++ で集合交差を検索

  1. C++ で集合の交差を見つけるには std::set_intersection メソッドを使用する
  2. C++ でセット対称差を求めるには std::set_symmetric_difference メソッドを用いる

この記事では、C++ で集合の共通部分を見つける方法のいくつかの方法について説明します。

C++ で集合の交差を見つけるには std::set_intersection メソッドを使用する

std::set_intersection メソッドは C++ アルゴリズムライブラリの一部であり、 <algorithm> ヘッダに含まれています。set_intersection アルゴリズムの操作は std::set オブジェクトに限定されるものではなく、std::vector のような任意の範囲ベースのオブジェクトを処理することができます。set_intersection アルゴリズムに渡す前に、両方の入力範囲をソートしなければならないことに注意してください。

以下の例では、2つの std::set 変数を宣言し、任意の string 型の要素で初期化します。関数 set_intersection の最初の 4つのパラメータは対応するオブジェクトからの範囲イテレータであり、第 5 引数は計算された交点が格納される範囲の先頭です。この場合、これらの要素を保持するために std::vector を宣言します。

#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>

using std::cout; using std::endl;
using std::cin; using std::string;
using std::set; using std::vector;

template<typename T>
void printVectorElements(vector<T> &vec)
{
    cout << "{ ";
    for (const auto &item : vec) {
        cout << item << ", ";
    }
    cout << "\b\b }" << endl;
}

int main() {
    set<string> s1 {"array", "vector",
                    "deque", "list",
                    "set", "map",
                    "multimap", "span"};
    set<string> s2(s1);
    s2.insert("stack");
    s2.insert("queue");

    vector<string> s1s2_intsec;

    std::set_intersection(s1.begin(), s1.end(),
                          s2.begin(), s2.end(),
                          std::back_inserter(s1s2_intsec));

    cout << "s1 ∩ s2: ";
    printVectorElements(s1s2_intsec);

    exit(EXIT_SUCCESS);
}

出力:

s1 ∩ s2: ( array, deque, list, map, multimap, set, span, vector )

std::set_intersection はユーザが指定した通りに交差要素を格納しますが、入力範囲のいずれかと重複する範囲であってはなりません。もう一つ注意すべき重要な点は、出力先の範囲を指定する際に、交差要素を格納するのに十分なスペースを確保することです。このための柔軟な方法としては、動的配列 std::vector を用いて std::back_inserter メソッドを用いて要素をオブジェクトにプッシュする方法があります。メモリを確保せずに vector.begin() イテレータを指定した場合、アルゴリズムがセグメンテーションフォールトを起こす可能性があります。次の例では、vector オブジェクトに対する set_intersection メソッドを示します。

#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>

using std::cout; using std::endl;
using std::cin; using std::string;
using std::set; using std::vector;

template<typename T>
void printVectorElements(vector<T> &vec)
{
    cout << "{ ";
    for (const auto &item : vec) {
        cout << item << ", ";
    }
    cout << "\b\b }" << endl;
}

int main() {
    vector<int> v1v2_intsec;
    vector<int> v1 {9,7,5,1,2};
    vector<int> v2 {4,3,2,1,7,8};
    std::sort(v1.begin(), v1.end());
    std::sort(v2.begin(), v2.end());

    std::set_intersection(v1.begin(), v1.end(),
                          v2.begin(), v2.end(),
                          std::back_inserter(v1v2_intsec));
    cout << "v1 ∩ v2: ";
    printVectorElements(v1v2_intsec);

    exit(EXIT_SUCCESS);
}

出力:

v1 ∩ v2: ( 1, 2, 7 )

C++ でセット対称差を求めるには std::set_symmetric_difference メソッドを用いる

C++ 標準ライブラリのもう 1つのアルゴリズムは std::set_symmetric_difference であり、入力範囲のいずれかにのみ存在する要素を検索します。関数のパラメータは std::set_intersection メソッドと似ています。どちらのアルゴリズムもソートされた範囲を受け取り、見つかった要素もソートされた方法で保存します。デフォルトでは std::set コンテナにはソートされた要素が格納されていることに注意してください。したがって、入力範囲として直接渡すことができます。一方、std::vector の内容は、std::set_symmetric_difference で処理される前に明示的にソートされなければなりません。

#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>

using std::cout; using std::endl;
using std::cin; using std::string;
using std::set; using std::vector;

template<typename T>
void printVectorElements(vector<T> &vec)
{
    cout << "{ ";
    for (const auto &item : vec) {
        cout << item << ", ";
    }
    cout << "\b\b }" << endl;
}

int main() {
    vector<int> v1 {9,7,5,1,2};
    vector<int> v2 {4,3,2,1,7,8};
    std::sort(v1.begin(), v1.end());
    std::sort(v2.begin(), v2.end());

    vector<int> v1v2_symdif;
    std::set_symmetric_difference(v1.begin(), v1.end(),
                          v2.begin(), v2.end(),
                          std::back_inserter(v1v2_symdif));
    cout << "v1 △ v2: ";
    printVectorElements(v1v2_symdif);

    exit(EXIT_SUCCESS);
}

出力:

v1 △ v2: ( 3, 4, 5, 8, 9 )