web-dev-qa-db-fra.com

Algorithme d'intersection de liste efficace

Étant donné deux listes (pas nécessairement triées), quel est l'algorithme non récursif le plus efficace pour trouver l'intersection de ces listes?

71
David

Vous pouvez mettre tous les éléments de la première liste dans un ensemble de hachage. Ensuite, itérez le second et, pour chacun de ses éléments, vérifiez le hachage pour voir s'il existe dans la première liste. Si tel est le cas, affichez-le comme élément de l'intersection.

34
Frank

Vous voudrez peut-être jeter un œil aux filtres Bloom. Ce sont des vecteurs de bits qui donnent une réponse probabiliste si un élément est membre d'un ensemble. Définir l'intersection peut être implémenté avec une simple opération ET au niveau du bit. Si vous avez un grand nombre d'intersections nulles, le filtre Bloom peut vous aider à les éliminer rapidement. Cependant, vous devrez toujours recourir à l'un des autres algorithmes mentionnés ici pour calculer l'intersection réelle. http://en.wikipedia.org/wiki/Bloom_filter

21

sans hachage, je suppose que vous avez deux options:

  • La manière naïve va être de comparer chaque élément à tous les autres éléments. O (n ^ 2)
  • Une autre façon serait de trier d'abord les listes, puis de les parcourir: O (n lg n) * 2 + 2 * O (n)
9
Tom Ritter

D'après la liste des fonctionnalités d'eviews il semble qu'il supporte les fusions et jointures complexes (s'il s'agit de "join" comme dans la terminologie DB, il calculera une intersection). Maintenant, fouillez dans votre documentation :-)

De plus, eviews a son propre forum d'utilisateurs - pourquoi ne pas y demander_

7
zvrba

avec l'ensemble 1 construire un arbre de recherche binaire avec O(log n) et itérer ensemble2 et rechercher BST m X O(log n) si total O(log n) + O(m)+O(log n) ==> O(log n)(m+1)

6
khaja

en C++, les éléments suivants peuvent être essayés en utilisant la carte 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

Voici une autre solution possible que j'ai trouvée prend O(nlogn) en complexité temporelle et sans stockage supplémentaire. Vous pouvez le vérifier ici https: //Gist.github. com/445537

Voici comment cela fonctionne: en supposant que les ensembles ne contiennent aucune répétition, fusionnez tous les ensembles en un et triez-le. Parcourez ensuite l'ensemble fusionné et, à chaque itération, créez un sous-ensemble entre l'index actuel i et i + n où n est le nombre d'ensembles disponibles dans l'univers. Ce que nous recherchons en boucle est une séquence répétée de taille n égale au nombre d'ensembles dans l'univers.

Si ce sous-ensemble en i est égal à ce sous-ensemble en n, cela signifie que l'élément en i est répété n fois ce qui est égal au nombre total d'ensembles. Et comme il n'y a pas de répétitions dans un ensemble, cela signifie que chacun des ensembles contient cette valeur, nous l'ajoutons donc à l'intersection. Ensuite, nous décalons l'index de i + ce qui reste entre lui et n parce que certainement aucun de ces index ne va former une séquence répétitive.

3
Ayman Farhat

Commencez par trier les deux listes à l'aide de la fonction de tri rapide: O (n * log (n). Ensuite, comparez les listes en parcourant d'abord les valeurs les plus faibles, puis ajoutez les valeurs communes. Par exemple, dans 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

qui est O(max(n, m))n et m sont les tailles des listes.

EDIT: quicksort est récursif, comme dit dans les commentaires, mais il semble qu'il y ait non récursifimplémentations

2
Wookai

S'il existe un support pour sets (comme vous les appelez dans le titre) comme intégré, il existe généralement une méthode d'intersection.

Quoi qu'il en soit, comme quelqu'un a dit que vous pouviez le faire facilement (je ne posterai pas de code, quelqu'un l'a déjà fait) si vous avez trié les listes. Si vous ne pouvez pas utiliser la récursivité, il n'y a pas de problème. Il existe tri rapide sans récursivité implémentations.

1
Andrea Ambu

J'appuie l'idée de "décors". En JavaScript, vous pouvez utiliser la première liste pour remplir un objet, en utilisant les éléments de la liste comme noms. Ensuite, vous utilisez les éléments de liste de la deuxième liste et voyez si ces propriétés existent.

1
Nosredna

L'utilisation de sauter les pointeurs et instructions SSE peut améliorer l'efficacité de l'intersection des listes.

1
Wolf Garbe

Pourquoi ne pas implémenter votre propre table de hachage ou ensemble de hachage simple? Cela vaut la peine d'éviter l'intersection nlogn si vos listes sont grandes comme vous le dites.

Comme vous en savez un peu plus sur vos données au préalable, vous devriez pouvoir choisir une bonne fonction de hachage.

1
Imran

D'après la définition de la notation Big-Oh:

T (N) = O(f(N)) s'il y a des constantes positives c et n 0 telles que T(N) ≤ cf (N) lorsque N ≥ n 0.

Ce qui signifie en pratique que si les deux listes sont relativement petites, dites quelque chose de moins 100 éléments dans chacune des deux pour les boucles fonctionne très bien. Bouclez la première liste et recherchez un objet similaire dans la seconde. Dans mon cas, cela fonctionne très bien car je n'aurai pas plus de 10 à 20 éléments max dans mes listes. Cependant, une bonne solution est de trier le premier O (n log n), de trier le second également O (n log n) et de les fusionner, un autre O (n log n) speeking grossièrement O (3 n log n), disons que les deux listes ont la même taille.

0
Adelin

J'ai reçu de bonnes réponses de this que vous pourriez appliquer. Je n'ai pas encore eu l'occasion de les essayer, mais comme ils couvrent également les intersections, vous pouvez les trouver utiles.

0
StingyJack