HashSet ist viel schneller als TreeSet (konstante Zeit gegenüber Protokollzeit für die meisten Vorgänge wie Hinzufügen, Entfernen und Enthalten), bietet jedoch keine Bestellgarantien wie TreeSet.
- Die Klasse bietet eine konstante Zeitleistung für die grundlegenden Operationen (Hinzufügen, Entfernen, Enthalten und Größe).
- Es kann nicht garantiert werden, dass die Reihenfolge der Elemente über die Zeit konstant bleibt
- Die Iterationsleistung hängt von der Anfangskapazität und dem Auslastungsfaktor des HashSet ab.
- Es ist ziemlich sicher, den Standardladefaktor zu akzeptieren, aber Sie können eine Anfangskapazität angeben, die ungefähr doppelt so groß ist, wie Sie erwarten, dass der Satz wächst.
- garantiert log (n) Zeitkosten für die Grundoperationen (Hinzufügen, Entfernen und Enthalten)
- garantiert, dass Elemente der Menge sortiert werden (aufsteigend, natürlich oder von Ihnen über den Konstruktor angegeben) (implementiert)
SortedSet
)
- bietet keine Optimierungsparameter für die Iterationsleistung
- bietet ein paar praktischen Methoden mit der geordneten Menge zu tun , wie
first()
, last()
, headSet()
, und tailSet()
etc
Wichtige Punkte:
- Beide garantieren eine doppelte Sammlung von Elementen
- Im Allgemeinen ist es schneller, Elemente zum HashSet hinzuzufügen und die Sammlung dann in ein TreeSet zu konvertieren, um eine duplikationsfreie sortierte Durchquerung zu erzielen.
- Keine dieser Implementierungen ist synchronisiert. Das heißt, wenn mehrere Threads gleichzeitig auf eine Gruppe zugreifen und mindestens einer der Threads die Gruppe ändert, muss sie extern synchronisiert werden.
- LinkedHashSet liegt in gewisser Weise zwischen
HashSet
und TreeSet
. Es wird als Hash-Tabelle implementiert, durch die eine verknüpfte Liste läuft. Es bietet jedoch eine Iteration in Einfügungsreihenfolge, die nicht mit der von TreeSet garantierten sortierten Durchquerung identisch ist .
Die Wahl der Verwendung hängt also ganz von Ihren Anforderungen ab, aber ich bin der Meinung, dass Sie HashSet auch dann bevorzugen sollten, wenn Sie eine geordnete Sammlung benötigen, um das Set zu erstellen und es dann in TreeSet zu konvertieren.
- z.B
SortedSet<String> s = new TreeSet<String>(hashSet);
Ein Vorteil, der von a noch nicht erwähnt wurde,
TreeSet
besteht darin, dass es eine größere "Lokalität" hat, was kurz gesagt ist: (1) Wenn zwei Einträge in der ReihenfolgeTreeSet
nahe beieinander liegen , platziert a sie in der Datenstruktur und damit im Speicher nahe beieinander; und (2) diese Platzierung nutzt das Prinzip der Lokalität, das besagt, dass auf ähnliche Daten häufig von einer Anwendung mit ähnlicher Häufigkeit zugegriffen wird.Dies steht im Gegensatz zu a
HashSet
, das die Einträge im gesamten Speicher verteilt, unabhängig von ihren Schlüsseln.Wenn die Latenzkosten für das Lesen von einer Festplatte das Tausendfache der Kosten für das Lesen aus dem Cache oder RAM betragen und wenn auf die Daten tatsächlich lokal zugegriffen wird,
TreeSet
kann dies eine viel bessere Wahl sein.quelle
TreeSet
/ durch OpenJDKTreeMap
nicht lokalitätsoptimiert. Während es möglich ist, einen B-Baum der Ordnung 4 zu verwenden, um einen Rot-Schwarz-Baum darzustellen und somit die Lokalität und die Cache-Leistung zu verbessern, funktioniert die Implementierung nicht so. Stattdessen speichert jeder Knoten einen Zeiger auf seinen eigenen Schlüssel, seinen eigenen Wert, seinen übergeordneten Knoten sowie seinen linken und rechten untergeordneten Knoten, was im JDK 8-Quellcode für TreeMap.Entry ersichtlich ist .HashSet
ist O (1), um auf Elemente zuzugreifen, also ist es sicherlich wichtig. Es ist jedoch nicht möglich, die Reihenfolge der Objekte im Set beizubehalten.TreeSet
ist nützlich, wenn die Aufrechterhaltung einer Reihenfolge (in Bezug auf Werte und nicht die Einfügereihenfolge) für Sie von Bedeutung ist. Wie Sie bereits bemerkt haben, tauschen Sie die Order für eine langsamere Zeit, um auf ein Element zuzugreifen: O (log n) für grundlegende Operationen.Aus den Javadocs für
TreeSet
:quelle
1.HashSet erlaubt Nullobjekt.
2.TreeSet lässt kein Nullobjekt zu. Wenn Sie versuchen, einen Nullwert hinzuzufügen, wird eine NullPointerException ausgelöst.
3.HashSet ist viel schneller als TreeSet.
z.B
quelle
null
zu Ihrem Set hinzufügen .TreeSet<String> badassTreeSet = new TreeSet<String>(new Comparator<String>() { public int compare(String string1, String string2) { if (string1 == null) { return (string2 == null) ? 0 : -1; } else if (string2 == null) { return 1; } else { return string1.compareTo(string2); } } }); badassTreeSet.add("tree"); badassTreeSet.add("asdf"); badassTreeSet.add(null); badassTreeSet.add(null); badassTreeSet.add("set"); badassTreeSet.add("tree"); System.out.println(badassTreeSet);
Basierend auf einer schönen visuellen Antwort auf Karten von @shevchyk hier ist meine Einstellung:
quelle
Der Grund, warum am häufigsten verwendet
HashSet
wird, ist, dass die Operationen (im Durchschnitt) O (1) anstelle von O (log n) sind. Wenn das Set Standardelemente enthält, werden Sie nicht "mit Hash-Funktionen herumspielen", wie dies für Sie getan wurde. Wenn der Satz benutzerdefinierte Klassen enthält, müssen Sie ihn implementieren, um ihnhashCode
zu verwendenHashSet
(obwohl Effective Java zeigt, wie), aber wenn Sie a verwendenTreeSet
, müssen Sie ihn erstellenComparable
oder a angebenComparator
. Dies kann ein Problem sein, wenn die Klasse keine bestimmte Reihenfolge hat.Ich habe manchmal verwendet
TreeSet
(oder tatsächlichTreeMap
) für sehr kleine Sets / Karten (<10 Elemente) verwendet, obwohl ich nicht überprüft habe, ob dies einen echten Gewinn bringt. Bei großen Sets kann der Unterschied erheblich sein.Wenn Sie nun die Sortierung benötigen,
TreeSet
ist dies angemessen. Auch wenn Aktualisierungen häufig sind und nur selten ein sortiertes Ergebnis erforderlich ist, kann es manchmal schneller sein, den Inhalt in eine Liste oder ein Array zu kopieren und zu sortieren.quelle
Wenn Sie nicht genügend Elemente einfügen, um häufige Wiederholungen (oder Kollisionen, wenn die Größe Ihres HashSet nicht geändert werden kann) durchzuführen, bietet Ihnen ein HashSet mit Sicherheit den Vorteil eines konstanten zeitlichen Zugriffs. Bei Sets mit viel Wachstum oder Schrumpfung erzielen Sie mit Treesets je nach Implementierung möglicherweise eine bessere Leistung.
Die amortisierte Zeit kann mit einem funktionierenden rot-schwarzen Baum nahe an O (1) liegen, wenn mir das Gedächtnis dient. Okasakis Buch hätte eine bessere Erklärung, als ich durchziehen kann. (Oder siehe seine Publikationsliste )
quelle
HashSet-Implementierungen sind natürlich viel schneller - weniger Overhead, da keine Bestellung erfolgt. Eine gute Analyse der verschiedenen Set-Implementierungen in Java finden Sie unter http://java.sun.com/docs/books/tutorial/collections/implementations/set.html .
Die Diskussion dort zeigt auch einen interessanten "Mittelweg" -Ansatz für die Tree vs Hash-Frage auf. Java stellt ein LinkedHashSet bereit, bei dem es sich um ein HashSet handelt, durch das eine "einfügeorientierte" verknüpfte Liste läuft. Das heißt, das letzte Element in der verknüpften Liste ist auch das zuletzt in den Hash eingefügte. Auf diese Weise können Sie die Unregelmäßigkeit eines ungeordneten Hashs vermeiden, ohne die erhöhten Kosten eines TreeSet zu verursachen.
quelle
Das TreeSet ist eine von zwei sortierten Sammlungen (die andere ist TreeMap). Es verwendet eine rot-schwarze Baumstruktur (aber das wussten Sie) und garantiert, dass die Elemente in aufsteigender Reihenfolge gemäß der natürlichen Reihenfolge sind. Optional können Sie ein TreeSet mit einem Konstruktor erstellen, mit dem Sie der Sammlung mithilfe eines Vergleichs- oder Komparators Ihre eigenen Regeln für die Reihenfolge zuweisen können (anstatt sich auf die durch die Elementklasse definierte Reihenfolge zu verlassen)
und Ein LinkedHashSet ist eine geordnete Version von HashSet, die eine doppelt verknüpfte Liste über alle Elemente hinweg verwaltet. Verwenden Sie diese Klasse anstelle von HashSet, wenn Sie sich für die Iterationsreihenfolge interessieren. Wenn Sie ein HashSet durchlaufen, ist die Reihenfolge nicht vorhersehbar, während Sie mit einem LinkedHashSet die Elemente in der Reihenfolge durchlaufen können, in der sie eingefügt wurden
quelle
Aufgrund technischer Überlegungen, insbesondere in Bezug auf die Leistung, wurden viele Antworten gegeben. Meiner Meinung nach ist die Wahl zwischen
TreeSet
undHashSet
wichtig.Aber ich würde eher sagen, dass die Wahl zuerst von konzeptionellen Überlegungen bestimmt werden sollte.
Wenn für die Objekte, die Sie manipulieren müssen, eine natürliche Reihenfolge keinen Sinn ergibt, verwenden Sie sie nicht
TreeSet
.Es ist eine sortierte Menge, da es implementiert
SortedSet
. Es bedeutet also, dass Sie die Funktion überschreiben müssencompareTo
, was mit der Rückgabefunktion übereinstimmen sollteequals
. Wenn Sie zum Beispiel eine Reihe von Objekten einer Klasse namens Student haben, dann denke ich nicht, dass aTreeSet
sinnvollen , da es keine natürliche Reihenfolge zwischen den Schülern gibt. Sie können sie nach ihrer Durchschnittsnote bestellen, okay, aber dies ist keine "natürliche Reihenfolge". FunktioncompareTo
die 0 nicht nur zurückgibt, wenn zwei Objekte denselben Schüler darstellen, sondern auch, wenn zwei verschiedene Schüler dieselbe Note haben. Für den zweiten Fallequals
würde false zurückgeben (es sei denn, Sie entscheiden sich dafür, dass letztere true zurückgeben, wenn zwei verschiedene Schüler dieselbe Note haben, wodurch dieequals
Funktion eine irreführende Bedeutung hat, um keine falsche Bedeutung zu sagen.)Bitte beachten Sie, dass diese Konsistenz zwischen
equals
undcompareTo
optional ist, aber stark empfohlen. Ansonsten der Vertrag der SchnittstelleSet
unterbrochen, wodurch Ihr Code für andere Personen irreführend wird und möglicherweise auch zu unerwartetem Verhalten führt.Dieser Link könnte eine gute Informationsquelle zu dieser Frage sein.
quelle
Warum Äpfel haben, wenn Sie Orangen haben können?
Ernsthaft Jungs und Mädels - wenn Ihre Sammlung groß ist, millionenfach gelesen und geschrieben wird und Sie für CPU-Zyklen bezahlen, ist die Auswahl der Sammlung NUR dann relevant, wenn Sie eine bessere Leistung benötigen. In den meisten Fällen spielt dies jedoch keine Rolle - einige Millisekunden bleiben hier und da menschlich unbemerkt. Wenn es wirklich so wichtig ist, warum schreiben Sie dann keinen Code in Assembler oder C? [Stichwort eine weitere Diskussion]. Der Punkt ist also, wenn Sie glücklich sind, die von Ihnen ausgewählte Sammlung zu verwenden, und dies Ihr Problem löst (auch wenn es nicht speziell die beste Art von Sammlung für die Aufgabe ist), sich selbst auszuschalten. Die Software ist formbar. Optimieren Sie Ihren Code bei Bedarf. Onkel Bob sagt, vorzeitige Optimierung sei die Wurzel allen Übels. Onkel Bob sagt es
quelle
Nachrichtenbearbeitung ( vollständiges Umschreiben ) Wenn die Reihenfolge keine Rolle spielt, ist dies der Zeitpunkt. Beide sollten Log (n) geben - es wäre nützlich zu sehen, ob einer über fünf Prozent schneller ist als der andere. HashSet kann O (1) -Tests in einer Schleife geben, sollte zeigen, ob dies der Fall ist.
quelle
quelle