Wenn Sie einfach nur wissen möchten, ob die Mengen gleich sind, wird die equals
Methode on AbstractSet
ungefähr wie folgt implementiert:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection c = (Collection) o;
if (c.size() != size())
return false;
return containsAll(c);
}
Beachten Sie, wie die häufigsten Fälle optimiert werden, in denen:
- Die beiden Objekte sind gleich
- das andere Objekt ist überhaupt keine Menge, und
- Die Größen der beiden Sets sind unterschiedlich.
Danach containsAll(...)
wird zurückgegeben false
, sobald ein Element in der anderen Gruppe gefunden wird, das sich nicht ebenfalls in dieser Gruppe befindet. Wenn jedoch alle Elemente in beiden Sätzen vorhanden sind, müssen alle getestet werden.
Die Worst-Case-Leistung tritt daher auf, wenn die beiden Sätze gleich, aber nicht dieselben Objekte sind. Diese Kosten sind in der Regel O(N)
oder O(NlogN)
abhängig von der Implementierung von this.containsAll(c)
.
Und Sie erhalten eine nahezu Worst-Case-Leistung, wenn die Sets groß sind und sich nur in einem winzigen Prozentsatz der Elemente unterscheiden.
AKTUALISIEREN
Wenn Sie bereit sind, Zeit in eine benutzerdefinierte Set-Implementierung zu investieren, gibt es einen Ansatz, der den "fast gleichen" Fall verbessern kann.
Die Idee ist, dass Sie einen Hash für den gesamten Satz vorberechnen und zwischenspeichern müssen, damit Sie den aktuellen Hashcode-Wert des Satzes erhalten O(1)
. Dann können Sie den Hashcode für die beiden Sätze als Beschleunigung vergleichen.
Wie könnten Sie einen solchen Hashcode implementieren? Nun, wenn der eingestellte Hashcode war:
- Null für eine leere Menge und
- das XOR aller Element-Hashcodes für eine nicht leere Menge,
Dann können Sie den zwischengespeicherten Hashcode des Sets jedes Mal, wenn Sie ein Element hinzufügen oder entfernen, kostengünstig aktualisieren. In beiden Fällen XOR Sie einfach den Hashcode des Elements mit dem aktuell eingestellten Hashcode.
Dies setzt natürlich voraus, dass Element-Hashcodes stabil sind, während die Elemente Mitglieder von Mengen sind. Es wird auch davon ausgegangen, dass die Hashcode-Funktion der Elementklassen eine gute Streuung ergibt. Dies liegt daran, dass Sie bei gleichen zwei gesetzten Hashcodes immer noch auf den O(N)
Vergleich aller Elemente zurückgreifen müssen .
Sie könnten diese Idee etwas weiter führen ... zumindest theoretisch.
WARNUNG - Dies ist sehr spekulativ. Ein "Gedankenexperiment", wenn Sie möchten.
Angenommen, Ihre Set-Element-Klasse verfügt über eine Methode zum Zurückgeben von Krypto-Prüfsummen für das Element. Implementieren Sie nun die Prüfsummen der Menge, indem Sie die für die Elemente zurückgegebenen Prüfsummen XOR-verknüpfen.
Was kauft uns das?
Wenn wir davon ausgehen, dass nichts hinter uns liegt, beträgt die Wahrscheinlichkeit, dass zwei ungleiche Mengenelemente die gleichen N-Bit-Prüfsummen haben, 2 -N . Und die Wahrscheinlichkeit, dass 2 ungleiche Mengen die gleichen N-Bit-Prüfsummen haben, beträgt ebenfalls 2 -N . Meine Idee ist also, dass Sie Folgendes implementieren können equals
:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection c = (Collection) o;
if (c.size() != size())
return false;
return checksums.equals(c.checksums);
}
Unter den oben genannten Annahmen erhalten Sie nur einmal in 2- N- Zeit die falsche Antwort . Wenn Sie N groß genug machen (z. B. 512 Bit), wird die Wahrscheinlichkeit einer falschen Antwort vernachlässigbar (z. B. ungefähr 10-150 ).
Der Nachteil ist, dass die Berechnung der Krypto-Prüfsummen für Elemente sehr teuer ist, insbesondere wenn die Anzahl der Bits zunimmt. Sie brauchen also wirklich einen effektiven Mechanismus zum Speichern der Prüfsummen. Und das könnte problematisch sein.
Und der andere Nachteil ist, dass eine Fehlerwahrscheinlichkeit ungleich Null inakzeptabel sein kann, egal wie gering die Wahrscheinlichkeit ist. (Aber wenn das der Fall ist ... wie gehen Sie mit dem Fall um, in dem ein kosmischer Strahl ein kritisches Bit umdreht? Oder wenn er in zwei Fällen eines redundanten Systems gleichzeitig dasselbe Bit umdreht?)