2015-01-13 11 views
6

Ho il seguente codice sul mio metodo main e quando eseguo l'iterazione tramite Set e stampo i valori, i valori sono già ordinati. Per quale motivo?Perché la classe HashSet <T> ha già dei valori ordinati quando utilizzo l'iteratore?

Set<Integer> set = new HashSet<Integer>(); 
set.add(2); 
set.add(7); 
set.add(3); 
set.add(9); 
set.add(6); 

for(int i : set) { 
    System.out.println(i); 
} 

uscita:

2 
3 
6 
7 
9 
+0

Si potrebbe provare ad aggiungere i numeri in un ordine diverso e vedere se l'uscita rimane la stessa. Ma come dicono le risposte, non c'è alcuna garanzia circa l'ordine, e quindi è solo una coincidenza :) – MinecraftShamrock

+0

Contrariamente alle attuali risposte, non è davvero un incidente o una coincidenza; ma scoprirai che non accadrà generalmente se metti alcuni numeri più grandi nel set, o una combinazione di numeri negativi e positivi. –

risposta

4

Questo è solo una coincidenza. A HashSet non conserva o garantisce alcun ordine.

Non fornisce garanzie sull'ordine di iterazione dell'insieme; in particolare in , non garantisce che l'ordine rimanga costante nel tempo .

+3

Non è un caso. Si tratta di un'implementazione di 'hashCode' in' Integer'. – NiematojakTomasz

+1

@NiematojakTomasz 'HashSet' esegue un hashing aggiuntivo per distribuire' hashCode' sulla quantità limitata di bucket che mantiene. Quella implementazione è sottratta, ecco perché sto dicendo che è una coincidenza. –

+1

@NiematojakTomasz: È una coincidenza. Ad esempio, l'effetto dell'hashing eseguito negli interni di 'HashSet', (di solito) rovinerebbe l'ordine degli interi. –

2

Questo è solo un incidente. Ho provato:

final Set<Integer> set = new HashSet<Integer>(); 
set.add(2); 
set.add(17); 
set.add(32); 
set.add(92); 
set.add(63); 

e ho ottenuto 17 32 2 92 63. Non era nell'ordine ordinato poiché HashSet non conserva l'ordine ordinato o l'ordine in cui sono stati aggiunti.

+1

Sì, hai ragione. Grazie (: – Sddf

+1

@MariaGabriela Se vuoi che i numeri siano ordinati tutto ciò che devi fare è usare un 'TreeSet . –

+1

@fastcodejava Qual è la complessità del tempo che utilizza TreeSet per ordinare i numeri? – Sddf

4

Non sono sicuro di chiamarlo una coincidenza è la risposta giusta. Non c'è alcuna possibilità in gioco. Risulterà dalle funzioni di hash utilizzate, dai piccoli valori inseriti nell'HashSet e dalla piccola quantità di elementi inseriti nel Set.

  • Per intero, hashCode() è il valore int del numero intero.

  • HashMap (e HashSet) eseguono un hashing aggiuntivo sul valore restituito da hashCode, ma questo hashing aggiuntivo non modifica il valore per numeri così piccoli come aggiunti a HashSet.

  • Infine, il bucket su cui ogni intero è inserito è il codice hash modificato che modula la capacità di HashSet. La capacità iniziale di un HashSet/HashMap è 16.

  • Pertanto 2 è aggiunto alla benna 2, 7, è aggiunto tazza 7, ecc ...

  • Quando eseguire iterazioni su elementi del HashSet, i bucket vengono visitati in ordine e, poiché ciascun bucket ha al massimo un singolo elemento, i numeri vengono ordinati.

Ecco come il segmento viene calcolato:

int hash = hash(key.hashCode()); 
int i = indexFor(hash, table.length); 

static int hash(int h) { // for the small integers you put in the set, all the values being 
         // xored with h are 0, so hash(h) returns h 
    h ^= (h >>> 20)^(h >>> 12); 
    return h^(h >>> 7)^(h >>> 4); 
} 

static int indexFor(int h, int length) { 
    return h & (length-1); // table.length is the initial capacity - 16, 
          // so for h <= 15, indexFor(h,table.length)=h 
} 

Pertanto, i secchi di 2,7,3,9,6 2,7,3,9,6 sono rispettivamente.

Il ciclo potenziato per l'iterazione su HashSet visita i bucket in ordine e per ciascun segmento scorre sopra le voci (che sono memorizzate in un elenco collegato). Pertanto, per il tuo input, 2 viene visitato per primo, seguito da 3, 6, 7 e 9.

Se si aggiungono i numeri superiori a 15, sia il metodo e il metodo hashindexFor (supponendo che non è stato modificato la capacità di default del HashSet) impedirebbe i numeri da essere ordinati quando iterato per l'iteratore HashSet.

+0

Buone informazioni, +1. Hai dato il codice dall'algoritmo di hashing JDK 6 È interessante notare che, anche se il calcolo del bucket cambia da JDK 6 a 7 a 8, i bucket per i numeri interi da 0 a 15 rimangono gli stessi, tuttavia il bucket calcolato differirà in Java 8 da quello di Java 6 e 7 per gli interi 16 e fino – rgettman

+0

@rgettman Ho solo cercato su Google il codice e ho ottenuto l'algoritmo JDK 6. – Eran