Avertissement: je sais qu'il y a déjà des questions de sondage similaires ici et sur Stackoverflow. Mais ce sont toutes des collisions, ce qui n'est pas ce que je demande.
Ma question est: pourquoi est par collision moins lookup O(1)
en premier lieu?
Supposons que j'ai cette table de hachage:
Hash Content
-------------
ghdjg Data1
hgdzs Data2
eruit Data3
xcnvb Data4
mkwer Data5
rtzww Data6
Maintenant, je cherche la clé k
où h(k)
donne la fonction de hachage h(k) = mkwer
. Mais comment la recherche "sait" que le hachage mkwer
est en position 5? Pourquoi ne doit-il pas faire défiler toutes les touches O(n)
pour le trouver? Les hachages ne peuvent pas être de véritables adresses matérielles car je perdrais la capacité de déplacer les données. Et pour autant que je sache, la table de hachage n'est pas triée sur les hachages (même si c'était le cas, la recherche prendrait également O(log n)
)?
En quoi la connaissance d'un hachage aide-t-elle à trouver la bonne place dans la table?
La fonction de hachage calcule la position du tableau à partir d'une chaîne donnée . Si c'est un hachage parfait, cela signifie qu'il n'y a certainement pas de collisions, le tableau est probablement au moins deux fois plus grand que le nombre d'éléments.
Par exemple, je donnerai un hachage très médiocre pour les lettres, juste pour illustrer le mécanisme:x=0;
x=xmod52
0) 1) pour chaque caractère de la chaîne, prendre la valeur ascii, soustraire «a» s'il est en minuscules, soustraire «A» si les majuscules, ajouter la valeur à x. 2) le nombre résultant, par exemple 15 est l'indice du tableau. x = x m o d 52
Ce hachage très simple (limité et sujet aux collisions) diffère des autres hachages par le mécanisme de hachage, ne tient pas compte de l'entrée donnée. Dans un schéma plus avancé, le hachage est un plus grand nombre, ajusté au nombre d'éléments. Un hachage parfait est généré pour toutes les entrées afin de garantir l'absence de collisions.
Il s'agit de car le calcul du hachage à partir d'une chaîne dépend de la sophistication de la fonction calculée, mais ne dépend pas du nombre d'éléments.O(1)
En cas de hachage parfait, lorsque des éléments sont ajoutés, est recalculé, le cas le plus simple avec des collisions lorsque la charge du tableau est grande, la taille du tableau augmente, la fonction prend un plus grand module de sortie et les éléments sont déplacés vers les nouveaux emplacements.h(k)
Le tableau est un fragment de mémoire continue, pour obtenir le élément, vous prenez l'adresse du premier élément (début du tableau), puis vous ajoutez à cette adresse pour avoir une cellule de mémoire explicite.n * ( de i z e o f e l e m e n t )n−th n∗(sizeofelement)
la source
Pour développer la réponse de David Richerby, le terme " fonction de hachage " est un peu surchargé. Souvent, lorsque nous parlons d'une fonction de hachage, nous pensons à MD5, SHA-1, ou quelque chose comme la
.hashCode()
méthode Java , qui transforme certaines entrées en un seul nombre. Cependant, le domaine de ce nombre (c'est-à-dire la valeur maximale) a très peu de chances d'être de la même taille que la table de hachage dans laquelle vous essayez de stocker des données. (MD5 est de 16 octets, SHA-1 est de 20 octets et.hashCode()
est unint
- 4 octets).Votre question porte donc sur la prochaine étape - une fois que nous avons une fonction de hachage qui peut mapper des entrées arbitraires sur des nombres, comment les placer dans une structure de données d'une taille particulière? Avec une autre fonction, également appelée "fonction de hachage"!
Un exemple trivial d'une telle fonction est modulo ; vous pouvez facilement mapper un certain nombre de tailles arbitraires à un index spécifique dans un tableau avec modulo. Ceci est introduit dans CLRS comme "la méthode de division":
Le modulo n'est donc pas une excellente fonction de hachage, car il limite les tailles que nous pouvons utiliser en toute sécurité pour notre structure de données sous-jacente. La section suivante présente une "méthode de multiplication" légèrement plus complexe, qui utilise également le modulo mais est avantageuse car "la valeur de n'est pas critique". Cependant, cela fonctionne mieux avec une connaissance préalable des «caractéristiques des données hachées» - quelque chose que nous ne savons souvent pas.m
Java
HashMap
utilise une version modifiée de la méthode de division qui effectue une étape de prétraitement pour tenir compte des.hashCode()
implémentations faibles afin de pouvoir utiliser des tableaux de taille deux. Vous pouvez voir exactement ce qui se passe dans la.getEntry()
méthode (les commentaires sont les miens):Java 8 a apporté une réécriture
HashMap
qui est encore plus rapide, mais un peu plus difficile à lire. Il utilise cependant le même principe général pour la recherche d'index.la source