È possibile velocizzare una tabella hash utilizzando alberi di ricerca binari per il concatenamento separato?


11

Voglio implementare una tabella hash utilizzando alberi di ricerca binaria per ridurre la complessità della ricerca nel processo di concatenamento separato da O (n) (utilizzando l'elenco collegato) a O (registro n) (utilizzando BST). Questo può essere fatto, e se sì, allora come? Sarebbe più facile capire se la soluzione è graduale, l'implementazione della logica.

Voglio ridurre il tempo di ricerca nella tabella hash (compilare usando il concatenamento separato), ma allo stesso tempo non voglio aumentare il tempo di inserimento. Per il mio progetto non posso modificare la funzione hash per ridurre le collisioni. Ma a causa della scalabilità, si verificano collisioni. Sto cercando di trovare un modo per aggirare, in modo da poter in qualche modo lavorare con il miglior accesso e inserire il tempo nel caso in cui si verifichi una collisione ... cioè per gestire lo stato attuale delle cose piuttosto che ristrutturare l'intero algoritmo. Se non esegue il pan out, sarà necessario ristrutturare. Quindi qualche idea?


4
Le tabelle hash e gli alberi di ricerca binaria sono contenitori diversi . Quindi non puoi fare ciò che suggerisci (o stai commettendo un errore terminologico).
Basile Starynkevitch

Immagino che potresti mettere una coppia hash / value in ciascun nodo di un albero ... ma sarebbe una tabella hash cattiva o un albero binario difettoso. Senza qualche chiarimento sul perché tu voglia fare tutto ciò e su cosa vuoi che il risultato finale sia in grado, non sono sicuro che questo sia veramente responsabile.
Ixrec,

1
@AK_: Sì, qualcosa del genere, come hai detto. voglio gestire le collisioni usando l'albero di ricerca binario. ho corretto un po 'la mia domanda per renderlo più chiaro.
Aviral,

1
Si noti che viene fornito con la penalità di O (n log n) per ogni inserimento quindi. In generale, quando hai una tabella hash che inizia a diventare troppo piena (e hai catene più lunghe di quanto puoi tollerare), ricostruisci l'hash. Se incontri regolarmente catene più lunghe di 3 o 4, qualcosa non va.

3
Esistono una miriade di variazioni nella tabella hash per la riduzione delle collisioni, l'indirizzamento aperto e il ridimensionamento dinamico della tabella. Quale si adatta alle tue esigenze è qualcosa che dovrai esaminare. Il tuo attuale approccio è trattato in

Risposte:


11

Quello che stai chiedendo è possibile dati i tuoi vincoli.

Analisi

Il punto di forza di una tabella hash è la sua velocità di ricerca e inserimento rapida. Per ottenere quella velocità, si deve rinunciare a qualsiasi parvenza di ordine nella tabella: cioè le voci sono tutte confuse. Un elenco è accettabile da utilizzare come voce di tabella poiché, sebbene l'attraversamento sia O (n), gli elenchi tendono ad essere brevi supponendo che la tabella hash sia sufficientemente grande e che gli oggetti memorizzati nella tabella siano sottoposti a hash utilizzando un algoritmo di hash di buona qualità.

Un albero di ricerca binario (BST) ha un rapido inserimento e ricerca in O (log 2 n). Impone inoltre una restrizione agli elementi che memorizza: deve esserci un modo per ordinare gli elementi. Dati due elementi A e B memorizzati nell'albero, deve essere possibile determinare se A precede B o se hanno un ordine equivalente.

Una tabella hash non impone tale restrizione: gli elementi in una tabella hash devono avere due proprietà. Innanzitutto, ci deve essere un modo per determinare se sono equivalenti; secondo, ci deve essere un modo per calcolare un codice hash deterministico. L'ordine non è un requisito.

Se gli elementi della tabella hash hanno un ordine, è possibile utilizzare un BST come voce della tabella hash per contenere oggetti con lo stesso codice hash (collisioni). Tuttavia, a causa di un BST con ricerca e inserimento O (log 2 n), ciò significa che il caso peggiore per l'intera struttura (tabella hash più BST) è tecnicamente migliore dell'uso di un elenco come voce di tabella. A seconda dell'implementazione di BST richiederà più spazio di archiviazione di un elenco, ma probabilmente non molto di più.

Si noti che normalmente l'overhead e il comportamento di un BST non portano nulla al tavolo nelle situazioni del mondo reale come secchi di tabella hash, motivo per cui le scarse prestazioni teoriche di un elenco sono accettabili. In altre parole, la tabella hash compensa la debolezza dell'elenco posizionando meno elementi in ciascun elenco (bucket). Tuttavia : il problema specificava che la tabella hash non può aumentare di dimensioni e che le collisioni sono più frequenti di quanto sia tipico in una tabella hash.

Implementazione

Non inserirò qui il codice perché onestamente non è davvero necessario e tu non hai dato una lingua comunque.

Quello che vorrei fare è semplicemente copiare qualsiasi tabella hash standard contenuta nella libreria standard della tua lingua in una nuova classe, quindi cambiare il tipo di bucket della tabella da un elenco a un albero. A seconda della lingua e della sua libreria standard, questa può essere una cosa molto banale da fare.

Normalmente non invoco a copiare e incollare la codifica in questo modo. Tuttavia, è un modo semplice per ottenere una struttura di dati testata in battaglia molto rapidamente.


In termini asintotici, l'uso di un albero binario per la gestione delle collisioni non modifica le prestazioni previste di una tabella hash, a condizione che la tabella hash abbia già eseguito i consueti trucchi per ottenere comunque prestazioni O (1) ammortizzate. Ridimensionare l'hashtable per garantire buone prestazioni significa che anche gli articoli previsti per bucket (la dimensione degli alberi binari) dovrebbero essere piccoli, quindi si finisce con lo stesso O ammortizzato atteso in entrambi i modi. Anche nel caso peggiore - senza alcun vincolo di bilanciamento specificato, le prestazioni nel caso peggiore per un albero binario sono che si comporta comunque come un elenco collegato.
Steve314,

@ Steve314 Tieni presente che il problema è che ci sono molte collisioni, quindi si aspetta che un bucket contenga più elementi rispetto a una tabella di hash normalmente.

Un buon punto - ad es. Per una tabella hash di dimensioni costanti con dati illimitati, le prestazioni asintotiche della tabella hash sono le stesse delle prestazioni asintotiche della gestione delle collisioni - la tabella hash modifica solo i fattori costanti.
Steve314,

@ Steve314, in sostanza, essenzialmente se la tabella hash non è in grado di limitare efficacemente il numero di elementi in ciascun bucket, le prestazioni asintotiche si riducono in qualunque struttura di sotto-dati viene utilizzata in ciascun bucket. Ho aggiunto un paragrafo alla mia risposta per chiarire questo punto.

7

L'uso di un albero binario per la gestione delle collisioni in una tabella hash non è solo possibile, ma è stato fatto.

Walter Bright è meglio conosciuto come l'inventore del linguaggio di programmazione D , ma ha anche scritto una variante ECMAScript chiamata DMDScript . In passato, un titolo principale di DMDScript (o forse un antenato - mi sembra di ricordare il nome DScript) era che i suoi hashtable tendevano a superare quelli in molti linguaggi simili. Il motivo: gestione delle collisioni mediante alberi binari.

Non ricordo esattamente da dove provenga, ma gli alberi utilizzati erano ingenui alberi binari, senza schema di equilibrio parziale (non AVL, rosso-nero o altro) che ha senso supponendo che la stessa hashtable venga ridimensionata quando diventa troppo piena e non si ottengono tassi assurdamente improbabili di collisioni di hash, gli alberi binari dovrebbero essere sempre piccoli. Fondamentalmente, il caso peggiore è sempre lo stesso dell'utilizzo di un elenco collegato per la gestione delle collisioni (tranne che si paga il prezzo di due puntatori per nodo anziché uno), ma il caso medio riduce la quantità di ricerca all'interno di ciascun bucket hash.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.