Schnittpunkt zweier Sätze in optimaler Weise

8

Bei zwei gegebenen Werten muss ich herausfinden, ob es ein gemeinsames Element gibt oder nicht, d. h. ob ihre Schnittmenge null ist oder nicht.

Welche der standardmäßigen C # -Sammlungen werden für diesen Zweck am besten (in Bezug auf die Leistung) geeignet sein? Ich weiß, dass linq eine Intersect Erweiterungsmethode hat, um die Schnittmenge zweier Listen / Arrays herauszufinden, aber mein Fokus liegt auf der Leistung in Big-O notation .

Und wenn ich auch die Schnittmenge zweier Sets herausfinden muss?

    
Ravi Gupta 25.01.2013, 17:55
quelle

2 Antworten

24

Nun, wenn Sie die Methode Intersect von LINQ verwenden, wird ein HashSet der zweiten Sequenz aufgebaut und dann jedes Element der ersten Sequenz dagegen geprüft. Also ist es O (M + N) ... und du kannst foo.Intersect(bar).Any() verwenden, um ein frühes Aus zu bekommen.

Wenn Sie einen (entweder) Wert in einem HashSet<T> speichern, um damit zu beginnen, können Sie natürlich einfach über den anderen iterieren, um in jedem Schritt nach Containment zu suchen. Sie müssten trotzdem das Set erstellen, um damit zu beginnen.

Grundsätzlich haben Sie ein O (M + N) -Problem, was auch immer Sie tun - Sie werden nicht billiger werden als das (es gibt immer die Möglichkeit, dass Sie sich ansehen müssen jedes Element) und wenn Ihre Hash-Codes vernünftig sind, sollten Sie in der Lage sein, diese Komplexität leicht zu erreichen. Natürlich können einige Lösungen bessere konstante Faktoren als andere geben ... aber das ist eher Leistung als Komplexität;)

EDIT: Wie in den Kommentaren erwähnt, gibt es auch ISet<T>.Overlaps - Wenn Sie bereits entweder einen statischen Typ von ISet<T> oder eine konkrete Implementierung festgelegt haben, wird durch Aufrufen von Overlaps deutlicher, was Sie tun. Wenn beide Ihrer Sätze statisch als ISet<T> eingegeben werden, verwenden Sie larger.Overlaps(smaller) (wobei größere und kleinere in Bezug auf die Größe der Menge sind), da ich eine Implementierung von Overlaps erwarten würde. iterieren Sie über das Argument und prüfen Sie jedes Element auf den Inhalt des Satzes, auf dem Sie es aufrufen.

    
Jon Skeet 25.01.2013, 17:57
quelle
2

Wie bereits erwähnt, erhalten Sie mit Any() eine gewisse Leistung.

Ich habe es an ziemlich großen Datensätzen getestet und es gab 25% Verbesserungen.

Es ist auch sehr wichtig, larger.Intersect(smaller) anstatt das Gegenteil anzuwenden, in meinem Fall hat es 35% Verbesserungen gegeben.

Auch die Reihenfolge der Liste vor dem Anwenden von Schnittpunkt ergab weitere 7-8%.

Beachten Sie auch, dass Sie je nach Anwendungsfall die Anwendung von Schnittpunkt vollständig vermeiden können.

Wenn beispielsweise für eine Integer-Liste das Maximum und das Minimum nicht innerhalb der gleichen Bounders liegen, müssen Sie keine Schnittmenge anwenden, da dies niemals der Fall ist.

Das gleiche gilt für eine String-Liste mit derselben Idee, die auf den ersten Buchstaben angewendet wird.

Versuchen Sie, je nach Ihrem Fall, so viel wie möglich, eine Regel zu finden, bei der es unmöglich ist, eine Kreuzung zu vermeiden.

    
badr slaoui 14.03.2017 11:51
quelle

Tags und Links