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

2つの集合が互いに素(Disjoint)かどうかを判定するアルゴリズム

2つの集合に共通する要素が1つも存在しないとき、それらは互いに素(disjoint set)であるといいます。言い換えると、2つの集合の積集合(共通部分)を求めた結果が空集合になる場合、その2つの集合は互いに素です。

判定方法は非常にシンプルです。このアルゴリズムでは、2つの集合が与えられ、どちらもすでにソート済みであると仮定します。そのうえで、両方の集合の要素を先頭から順番に比較していきます。一致する要素が1つでも見つかれば互いに素ではなく、最後まで一致する要素が存在しなければ、2つの集合は互いに素であると判定できます。

入力と出力

入力:
2つの集合:
set1: {15, 12, 36, 21, 14}
set2: {7, 89, 56, 32}

出力:
Both sets are disjoint(2つの集合は互いに素である)

アルゴリズム

isDisjoint(set1, set2)

入力: 2つの集合。

出力: 2つの集合が互いに素であれば true を返します。

Begin
    i1 := 最初の集合の先頭
    i2 := 2番目の集合の先頭
    while i1 が set1 内 かつ i2 が set2 内 の間、繰り返し:
        if set1[i1] < set2[i2] ならば
            i1 := i1 + 1
        else if set2[i2] < set1[i1] ならば
            i2 := i2 + 1
        else
            return false   // 要素が一致したため互いに素ではない
    return true
End

計算量について

この手法では、各集合のポインタ(イテレータ)が常に前へ進むだけなので、計算量は O(n + m)(n、m はそれぞれの集合の要素数)となります。全要素同士を総当たりで比較する O(n × m) よりも効率的です。なお、集合が未ソートの場合は事前にソートが必要で、その場合はソートのコストが加わります。

C++による実装例

#include<iostream>
#include<set>
using namespace std;

bool isDisjoint(set<int> set1, set<int> set2) {
    set<int>::iterator i1, i2;
    i1 = set1.begin(); i2 = set2.begin();          // イテレータを先頭要素で初期化
    while(i1 != set1.end() && i2 != set2.end()) {  // 両方の集合に確認すべき要素がある間
        if(*i1 < *i2)
            i1++;              // 第1集合の要素が小さい場合は次へ進む
        else if(*i2 < *i1)
            i2++;              // 第2集合の要素が小さい場合は次へ進む
        else
            return false;      // 要素が一致した → 互いに素ではない
    }
    return true;
}

int main() {
    set<int> set1, set2;
    int n1, n2;
    cout << "Enter number of elements in set 1: "; cin >>n1;

    while(n1 != set1.size()) {     // 重複した要素は自動的に除外される
        int item;
        cout << "Enter element: "; cin >> item;
        set1.insert(item);
    }

    cout << "Enter number of elements in set 2: "; cin >>n2;
    while(n2 != set2.size()) {
        int item;
        cout << "Enter element: "; cin >> item;
        set2.insert(item);
    }

    if(isDisjoint(set1, set2))
        cout << "Both sets are disjoint";
    else
        cout << "Sets are not disjoint";
}

ここでは C++ の std::set を使用しています。std::set は内部で要素が常にソートされた状態で保持されるため、このアルゴリズムの前提条件(ソート済み)を自然に満たせます。また、重複する値を挿入しても自動的に1つにまとめられる点にも注意してください。

実行結果

Enter number of elements in set 1: 5
Enter element: 15
Enter element: 12
Enter element: 36
Enter element: 21
Enter element: 14
Enter number of elements in set 2: 4
Enter element: 7
Enter element: 89
Enter element: 56
Enter element: 32
Both sets are disjoint

この例では、set1 = {12, 14, 15, 21, 36} と set2 = {7, 32, 56, 89} の間に共通要素が存在しないため、「Both sets are disjoint(互いに素である)」と正しく判定されています。

  1. Pythonで2つのリストが循環的に同一かどうかを判定する方法

    この記事では、2つのリストが与えられたとき、それらが循環的に同一(circularly identical)であるかどうかを判定するPythonプログラムを紹介します。循環的に同一とは、片方のリストの要素を回転させたとき、もう片方のリストと完全に一致する状態を指します。 実行例 入力 : A = [100, 100, 10, 10, 100] B = [100, 100, 100, 10, 10] 出力 : True 解説 リストAの要素を順番に循環的に回転させると、リストBと同じ並びになるため、結果は True となります。つまり、開始位置が異なるだけで、要素の並びのパター

  2. 【Python入門】2つの行列が同一かどうかを判定するプログラムの書き方

    この記事では、与えられた2つの行列(マトリックス)が同一であるかどうかを判定するPythonプログラムを紹介します。2つの行列が同一であるためには、次の条件を満たす必要があります。 両行列の行数・列数(次数)が一致していること 対応するすべての要素が等しいこと これらの条件を1つでも満たさない場合、2つの行列は同一とはみなされません。 アルゴリズム 判定の手順は以下の通りです。計算量は O(n²)(n×n行列の場合)となります。 ステップ1: 2つの行列を作成する。 ステップ2: 1つ目の行列と2つ目の行列のすべての要素を走査し、 対応する要素同士を順番に比較する