Effiziente Reihe Schnittpunkt einer Sammlung von Sätzen in C++

Habe ich eine Sammlung von std::set. Ich möchte zu finden, die Schnittmenge aller sets in dieser Sammlung, in der schnellsten Art und Weise. Die Anzahl der Sätze in der Sammlung ist in der Regel sehr klein (~5-10), und die Anzahl der Elemente in jedem Satz ist in der Regel weniger als 1000, kann aber gelegentlich gehen bis etwa 10000. Aber ich brauche zu tun diese Kreuzungen Zehntausende von Zeit, so schnell wie möglich. Ich versuchte benchmark ein paar Methoden wie folgt:

  1. In-place-Kreuzung in eine std::set Objekt, das zunächst kopiert den ersten Satz. Dann für den folgenden Sätzen, es iteriert über alle element der selbst-und der I-TEN Reihe von der Auflistung und entfernt Elemente aus sich selbst, wie benötigt werden.
  2. Mit std::set_intersection in eine temporäre std::set -, swap-Inhalte zu einem aktuellen Satz, dann wieder suchen Schnittpunkt der aktuelle Satz mit dem nächsten Satz und einfügen in die temp einstellen, und so weiter.
  3. Manuell iterieren über alle Elemente aller Mengen, wie in 1), aber mit einem vector als Ziel-container statt std::set.
  4. Gleichen wie in 4, aber mit einem std::list statt einer vector den Verdacht, dass ein list wird eine schnellere Löschungen aus der Mitte.
  5. Mit hash-sets (std::unordered_set) und überprüfen Sie für alle Elemente in allen sets.

Wie sich herausstellte, mit einem vector ist geringfügig schneller, wenn die Anzahl der Elemente in jeder Gruppe ist klein, und list ist geringfügig schneller für größere sets. In-place-mithilfe set ist wesentlich langsamer als die beiden, gefolgt von set_intersection - und hash-sets. Gibt es einen schnelleren Algorithmus/datastructure/tricks das zu erreichen? Ich kann nach code-snippets, falls erforderlich. Danke!

  • Die Frage hängt wirklich davon ab, ob oder nicht von Ihnen erwartet, finden viele gemeinsame Elemente, oder nicht, wie dies verändert die "beste" Struktur, die man mit oben kommen kann. Zum Beispiel, ein 6. Methode ist einfach zu benutzen und std::unordered_map und zählen der Anzahl der vorkommen der einzelnen Elemente. Es ist O(N) und die Gesamtzahl der Elemente. Sie dann, wählen Sie nur die Elemente, die insgesamt gleich der Anzahl der Sätze, O(M) die Anzahl der unterschiedlichen Elemente. Keine Ahnung, wie gut es durchführen würde.
  • Ich sehe. Ich geben diesem einen Versuch, obwohl ich vermute, es wird nicht schneller sein als ein std::list durch das hashing und die sonstigen Gemeinkosten. Danke!
  • Dieser Methode geben Sie die Ergebnismenge in unsortierter Reihenfolge. Zum Glück habe ich zwei Anwendungsfälle, eines für das Ergebnis in der Reihenfolge sortiert, und eine, die nicht. Wenn diese Methode ist Recht schnell, ich kann es atleast für den Fall, wo die Kreuzung ist nicht nötig, um sortiert werden.
  • Ich habe versucht, diesen Ansatz, und für meine Daten, das war nur geringfügig schneller als mein Ansatz 5 (mit unordered_set).
  • Sie könnten versuchen, die Idee. Schlimmsten Fall linear (lässt sich nicht vermeiden, dass, wenn die sets haben meist die gleichen Elemente), aber wenn die Schnittmenge klein ist, kann es viel schneller.
  • Danke!!! Aufgrund Dietmar, die Antwort unten, ich hatte auch darüber nachgedacht, eine binäre Suche wenn tut, Suche in arrays. Aber der Schlimmste Fall Verlangsamungen war eine Sorge. Sie schlagen vor, eine sehr schöne Heuristik/Einschätzung zu machen dies zu einem hybrid-Ansatz. In der Tat, dies ist nur geringfügig langsamer als die vector-Ansatz (pt 3 oben) durch kleine zusätzliche Berechnungen, aber klar der Schnellste unter allen, wenn Sie die Größen der nachfolgenden Sätze ist ausreichend größer als das aktuelle! Sehr schöne Idee!
  • Ich hätte akzeptiert, wenn es eine Antwort gab.
  • könnten wir einen Blick auf die Quelle des Tests?

InformationsquelleAutor Paresh | 2012-10-13
Schreibe einen Kommentar