Quelqu'un peut-il expliquer les principales différences entre (avantages/inconvénients) les deux implémentations?
Pour une bibliothèque, quelle implémentation est recommandée?
article de Wikipédia sur les tables de hachage donne une explication et une vue d'ensemble nettement meilleures des différents schémas de tables de hachage que les gens ont utilisés que je ne peux le faire. En fait, vous feriez probablement mieux de lire cet article que de poser la question ici. :)
Cela dit...
Une table de hachage chaînée indexe dans un tableau de pointeurs vers les têtes de listes liées. Chaque cellule de liste liée a la clé pour laquelle elle a été allouée et la valeur qui a été insérée pour cette clé. Lorsque vous souhaitez rechercher un élément particulier à partir de sa clé, le hachage de la clé est utilisé pour déterminer la liste liée à suivre, puis cette liste particulière est parcourue pour trouver l'élément que vous recherchez. Si plusieurs clés de la table de hachage ont le même hachage, alors vous aurez des listes liées avec plus d'un élément.
L'inconvénient du hachage chaîné est de devoir suivre des pointeurs pour rechercher des listes chaînées. L'avantage est que les tables de hachage chaînées ne deviennent linéairement plus lentes que lorsque le facteur de charge (le rapport des éléments de la table de hachage à la longueur du tableau de compartiments) augmente, même s'il dépasse 1.
Une table de hachage à adressage ouvert indexe dans un tableau de pointeurs vers des paires de (clé, valeur). Vous utilisez la valeur de hachage de la clé pour déterminer l'emplacement du tableau à examiner en premier. Si plusieurs clés de la table de hachage ont le même hachage, vous utilisez un schéma pour décider d'un autre emplacement à rechercher à la place. Par exemple, le sondage linéaire est l'endroit où vous regardez l'emplacement suivant après celui choisi, puis l'emplacement suivant après cela, et ainsi de suite jusqu'à ce que vous trouviez un emplacement correspondant à la clé que vous recherchez ou que vous frappiez un emplacement vide fente (auquel cas la clé ne doit pas être là).
L'adressage ouvert est généralement plus rapide que le hachage chaîné lorsque le facteur de charge est faible car vous n'avez pas à suivre les pointeurs entre les nœuds de liste. Cela devient très, très lent si le facteur de charge approche 1, car vous finissez généralement par rechercher dans de nombreux emplacements du tableau de compartiments avant de trouver la clé que vous recherchez ou un emplacement vide. En outre, vous ne pouvez jamais avoir plus d'éléments dans la table de hachage qu'il n'y a d'entrées dans le tableau de compartiment.
Pour faire face au fait que toutes les tables de hachage deviennent au moins plus lentes (et dans certains cas se cassent complètement) lorsque leur facteur de charge approche 1, les implémentations pratiques des tables de hachage agrandissent le tableau de seaux (en allouant un nouveau tableau de seaux et en copiant les éléments de l'ancien dans le nouveau, puis libérer l'ancien) lorsque le facteur de charge dépasse une certaine valeur (généralement environ 0,7).
Il y a beaucoup de variations sur tout ce qui précède. Encore une fois, veuillez consulter l'article wikipedia, c'est vraiment très bien.
Pour une bibliothèque destinée à être utilisée par d'autres personnes, je recommanderais fortement d'expérimenter. Puisqu'ils sont généralement assez cruciaux pour les performances, il est généralement préférable d'utiliser l'implémentation par quelqu'un d'autre d'une table de hachage qui a déjà été soigneusement réglée. Il existe de nombreuses implémentations de tables de hachage sous licence BSD, LGPL et GPL.
Si vous travaillez avec GTK, par exemple, vous constaterez qu'il existe une bonne table de hachage dans GLib .
Ma compréhension (en termes simples) est que les deux méthodes ont des avantages et des inconvénients, bien que la plupart des bibliothèques utilisent la stratégie de chaînage.
Méthode de chaînage:
Ici, le tableau des tables de hachage correspond à une liste d'éléments liée. Ceci est efficace si le nombre de collisions est assez faible. Le pire des cas est O(n)
où n est le nombre d'éléments dans la table.
Adressage ouvert avec sonde linéaire:
Ici, lorsque la collision se produit, passez à l'index suivant jusqu'à ce que nous trouvions un endroit ouvert. Donc, si le nombre de collisions est faible, c'est très rapide et peu encombrant. La limitation ici est que le nombre total d'entrées dans le tableau est limité par la taille du tableau. Ce n'est pas le cas avec le chaînage.
Il existe une autre approche qui est Chaînage avec des arbres de recherche binaires . Dans cette approche, lorsque la collision se produit, ils sont stockés dans un arbre de recherche binaire au lieu d'une liste liée. Par conséquent, le pire des cas ici serait O(log n)
. En pratique, cette approche est la mieux adaptée lorsqu'il existe une distribution extrêmement non uniforme.
Adressage ouvert vs chaînage séparé
Le sondage linéaire, le hachage double et aléatoire sont appropriés si les clés sont conservées en tant qu'entrées dans la table de hachage elle-même ... ce qui est appelé "adressage ouvert", il est également appelé "hachage fermé"
Autre idée: les entrées de la table de hachage ne sont que des pointeurs vers le début d'une liste chaînée ("chaîne"); les éléments de la liste chaînée contiennent les clés ... cela s'appelle "chaînage séparé" il est aussi appelé "hachage ouvert"
La résolution des collisions devient facile avec un chaînage séparé: il suffit d'insérer une clé dans sa liste chaînée si elle n'est pas déjà là (il est possible d'utiliser des structures de données plus sophistiquées que des listes chaînées pour cela; mais les listes chaînées fonctionnent très bien dans le cas moyen, comme nous verrons) Voyons à analyser les coûts de temps de ces stratégies
Source: http://cseweb.ucsd.edu/~kube/cls/100/Lectures/lec16/lec16-25.html