web-dev-qa-db-ja.com

効率的なリスト交差アルゴリズム

2つのリスト(必ずしもソートされているわけではない)が与えられた場合、それらのリストの共通部分を見つけるための最も効率的な非再帰的アルゴリズムは何ですか?

71
David

最初のリストのすべての要素をハッシュセットに入れることができます。次に、2番目の要素を繰り返し、各要素について、ハッシュをチェックして、最初のリストに存在するかどうかを確認します。その場合、交差点の要素として出力します。

34
Frank

ブルームフィルターをご覧ください。これらは、要素が集合のメンバーであるかどうかの確率的な答えを与えるビットベクトルです。集合交差は、単純なビット単位のAND演算で実装できます。ヌルの交差点が多数ある場合、ブルームフィルターを使用すると、それらをすばやく削除できます。ただし、実際の交差を計算するには、ここで説明した他のアルゴリズムのいずれかに頼る必要があります。 http://en.wikipedia.org/wiki/Bloom_filter

21

ハッシュせずに、2つのオプションがあると思います。

  • 素朴な方法は、各要素を他のすべての要素と比較することです。 O(n ^ 2)
  • 別の方法は、リストを最初にソートしてから、それらを反復することです:O(n lg n)* 2 + 2 * O(n)
9
Tom Ritter

eviews features list から、複雑なマージと結合をサポートしているようです(DBの用語のように「結合」の場合、交差を計算します)。今、あなたのドキュメントを掘り下げてください:-)

さらに、eviewsには独自のユーザーフォーラムがあります。

7
zvrba

セット1でO(log n)を使用してバイナリ検索ツリーを構築し、set2を反復してBST m X O(log n)を検索し、合計O(log n) + O(m)+O(log n) ==> O(log n)(m+1)

6
khaja

c ++では、STLマップを使用して以下を試すことができます。

vector<int> set_intersection(vector<int> s1, vector<int> s2){

    vector<int> ret;
    map<int, bool> store;
    for(int i=0; i < s1.size(); i++){

        store[s1[i]] = true;
    }
    for(int i=0; i < s2.size(); i++){

        if(store[s2[i]] == true) ret.Push_back(s2[i]);

    }
    return ret;
}
6
quasar

ここに、時間の複雑さと余分なストレージなしでテイクO(nlogn))を思いついた別の可能な解決策があります。ここで確認できます https://Gist.github。 com/445537

仕組みは次のとおりです。セットに繰り返しが含まれていないと仮定して、すべてのセットを1つにマージしてソートします。次に、マージされたセットをループし、各反復で現在のインデックスiとi + nの間のサブセットを作成します。nはユニバースで使用可能なセットの数です。ループするときに探すのは、宇宙の集合の数に等しいサイズnの繰り返しシーケンスです。

Iの部分集合がnの部分集合に等しい場合、これはiの要素がセットの総数に等しいn回繰り返されることを意味します。また、どのセットにも繰り返しがないため、各セットにはその値が含まれているため、交差に追加します。次に、インデックスをi + nとその間に残っているものだけシフトします。これらのインデックスはいずれも繰り返しシーケンスを形成しないためです。

3
Ayman Farhat

まず、quicksort:O(n * log(n)を使用して両方のリストをソートします。次に、最初に最小値を参照してリストを比較し、共通の値を追加します。たとえば、lua):

_function findIntersection(l1, l2)
    i, j = 1,1
    intersect = {}

    while i < #l1 and j < #l2 do
        if l1[i] == l2[i] then
            i, j = i + 1, j + 1
            table.insert(intersect, l1[i])
        else if l1[i] > l2[j] then
            l1, l2 = l2, l1
            i, j = j, i
        else
            i = i + 1
        end
    end

    return intersect
end
_

これはO(max(n, m))です。ここで、nmはリストのサイズです。

編集:コメントで述べたように、クイックソートは再帰的ですが、 非再帰的実装 があるように見えます

2
Wookai

sets のサポートがある場合(タイトルでそれらを呼び出すように)ビルトインとして、通常、intersectionメソッドがあります。

とにかく、リストがソートされていれば、誰かがあなたがそれを簡単にできると言ったように(私はコードを投稿しません、誰かがすでにそうしました)。再帰を使用できない場合は問題ありません。 クイックソート再帰なし の実装があります。

1
Andrea Ambu

2番目に「セット」のアイデアです。 JavaScriptでは、リスト要素を名前として使用して、最初のリストを使用してオブジェクトを作成できます。次に、2番目のリストのリスト要素を使用して、それらのプロパティが存在するかどうかを確認します。

1
Nosredna

スキップポインター および SSE命令 を使用すると、リストの交差の効率が向上します。

1
Wolf Garbe

独自の単純なハッシュテーブルまたはハッシュセットを実装してみませんか?あなたが言うようにリストが大きい場合、nlognの交差を避けることは価値があります。

事前にデータについて少し知っているので、適切なハッシュ関数を選択できるはずです。

1
Imran

Big-Oh表記の定義から:

T(N)= O(f(N))正の定数cとn 0があり、T(N)≤cf(N) N≥n 0の場合。

これは、実際には、2つのリストのサイズが比較的小さい場合、各2つのforループで100個未満の要素が問題なく機能することを意味します。最初のリストをループし、2番目のリストで同様のオブジェクトを探します。私の場合、リストには最大10-20個の要素しか含まれていないため、うまく機能します。しかし、良い解決策は、最初のO(n log n)をソートし、2番目のO(n log n)もソートしてそれらをマージすることです。別のO(n log n)はO(3 n log n) 2つのリストは同じサイズです。

0
Adelin

this からいくつかの良い答えが得られました。まだ試してみる機会はありませんが、交差点もカバーしているので、役に立つかもしれません。

0
StingyJack