2013-09-06 4 views
5

Der folgende Code erzeugt den Ausgang [1,2], obwohl hashset nicht sortiert ist.Wie erzeugt dieses HashSet eine sortierte Ausgabe?

Set set = new HashSet(); 
set.add(new Integer(2)); 
set.add(new Integer(1)); 
System.out.println(set); 

Warum ist das?

+0

Verwenden Sie mehrere Testfälle. Fügen Sie 20 Zahlen ein und sehen Sie, ob das Ergebnis gleich ist. – JNL

Antwort

8

durch mehrere getrennte Gründe Dieses Verhalten verursacht:

  • Integers Hash sich
  • in Java, HashMap s und HashSet s durch ein Array
  • sie auch Hashes ändern mit der höheren gesichert Bits, um die unteren Bits zu modifizieren; wenn der Hash im Bereich 0 liegt.15, ist es daher nicht geändert
  • was Eimer ein Objekt geht auf den unteren Bits des modifizierten Hash hängt
  • wenn über eine Karte oder einen Satz Iterieren, die innere Tabelle sequentiell abgetastet wird

Also, wenn Sie mehrere kleine (< 16) ganze Zahlen summieren sich zu einem hashmap/Hashset, das ist, was passiert:

  • integer i hat hashcode i
  • da es weniger t ist Han 16, ist es modifizierte Hash ist auch i
  • es landet in den Eimer nein. i
  • wenn iteriert werden die Schaufeln der Reihe nach besucht, so dass, wenn alles, was Sie dort gespeichert sind kleine ganze Zahlen sind, werden sie in aufsteigender Reihenfolge

Hinweis abgerufen werden, wenn die anfängliche Anzahl von Buckets zu klein ist, die ganzen Zahlen kann in Eimern landen nicht nach ihnen nummeriert:

HashSet<Integer> set = new HashSet<>(4); 
set.add(5); set.add(3); set.add(1); 
for(int i : set) { 
    System.out.print(i); 
} 

druckt 153.

1

Ein HashSet ist eine ungeordnete Sammlung. Es gibt keine Garantien und keine Konzepte von "Bestellung". Finden Sie diese Antwort für weitere Details: What is the difference between Set and List?

Sie können eine TreeSet verwenden, wenn Sie geordnete, sortierte Set benötigen.

Es gibt auch eine LinkedHashSet für ein sortiertes Set, das nicht sortiert ist.

+0

@superEb Ich habe gerade diesen Klappentext zu meiner Antwort hinzugefügt. Sieht so aus, als hätten wir es gleichzeitig bemerkt! – Kon

0

Eine set in Java soll nicht in der Liste bestellt werden. Verwenden Sie stattdessen ArrayList. Überprüfen Sie auch Java Collection API für weitere Referenz.

+0

Verwenden Sie jedoch keine 'List', wenn die Elemente eindeutig sein müssen. – superEb

+0

'LinkedHashSet' ist normalerweise eine bessere Wahl, wenn Sie schnelle (konstante-Zeit) Suchen, aber mit vorhersagbarer Iterationsreihenfolge wünschen. Verwenden Sie 'ArrayList' nur, wenn Sie Speicherplatz sparen und langsame (lineare) Lookups tolerieren können. –

+0

@Ashwin Beachten Sie, dass Sie logarithmische Zeit O (log n) nachschlagen Zeiten für eine sortierte Liste abrufen können, indem Sie die 'Collections.binarySearch()' Methode verwenden. – Kon

5

Ein HashSet gemäß der Dokumentation garantiert kein Konzept der Bestellung, also was Sie sehen, könnte sehr gut in einem zukünftigen Update von Java ändern.

Allerdings, wenn Sie sich fragen, warum Java (ab sofort) spezifische Implementierung HashSet das Ergebnis führt Sie sehen: es ist, weil die Integer Wert 1 Hashes zu einer Stelle im internen Eintragstabelle eines HashMap dass kommt vor der Ort, an dem 2 Hashwerte (beachten Sie, dass eine HashSet wirklich durch eine HashMap mit beliebigen Werten unterstützt wird). Dies ist sinnvoll, da der Hash-Code eines Integer Objekts nur seinen Wert hat.

In der Tat kann man dies auch sehen, wenn Sie noch mehr Zahlen addieren (innerhalb eines bestimmten Bereichs: die Größe der Eingabetabelle, die 16 ist standardmäßig):

Set<Integer> set = new HashSet<>(); 
set.add(2); 
set.add(1); 
set.add(4); 
set.add(3); 
set.add(0); 
System.out.println(set); 
 
[0, 1, 2, 3, 4] 

Iteration über eine HashSet erfolgt durch Iterieren über die interne Entry-Tabelle, was bedeutet, dass Elemente früher in der Tabelle zuerst kommen.