Je travaille sur une table de hachage en langage C et je teste la fonction de hachage pour la chaîne.
La première fonction que j'ai essayée est d'ajouter du code ascii et d'utiliser modulo (% 100) mais j'ai de mauvais résultats avec le premier test de données: 40 collisions pour 130 mots.
Les données d'entrée finales contiendront 8 000 mots (c'est un dictionnaire stocké dans un fichier). La table de hachage est déclarée comme int table [10000] et contient la position du mot dans un fichier txt.
La première question est quel est le meilleur algorithme pour la chaîne de hachage? et comment déterminer la taille de la table de hachage?
Merci d'avance !
:-)
Réponses:
J'ai eu de beaux résultats avec
djb2
par Dan Bernstein.la source
size_t
ou une autre valeur non signée (comme le long unsigned dans ce code). L' appelant est responsable de prendre modulo du résultat pour l'adapter à la table de hachage. L'appelant contrôle l'emplacement de table sur lequel le hachage est effectué; pas la fonction. Il renvoie juste un nombre non signé.Premièrement, vous ne souhaitez généralement pas utiliser de hachage cryptographique pour une table de hachage. Un algorithme très rapide par rapport aux normes cryptographiques est encore extrêmement lent par rapport aux normes de table de hachage.
Deuxièmement, vous voulez vous assurer que chaque bit de l'entrée peut / affectera le résultat. Un moyen simple de le faire est de faire pivoter le résultat actuel d'un certain nombre de bits, puis de XOR le code de hachage actuel avec l'octet actuel. Répétez jusqu'à ce que vous atteigniez la fin de la chaîne. Notez que vous ne souhaitez que la rotation soit un multiple pair de la taille d'octet.
Par exemple, en supposant le cas courant d'octets de 8 bits, vous pouvez effectuer une rotation de 5 bits:
Edit: Notez également que 10000 emplacements sont rarement un bon choix pour une taille de table de hachage. Vous voulez généralement l'une des deux choses suivantes: vous voulez soit un nombre premier comme taille (requis pour assurer l'exactitude avec certains types de résolution de hachage), soit une puissance de 2 (donc réduire la valeur à la plage correcte peut être fait avec un simple masque de bits).
la source
Wikipedia montre une belle fonction de hachage de chaîne appelée Jenkins One At A Time Hash. Il cite également des versions améliorées de ce hachage.
la source
Il existe un certain nombre d'implémentations de table de hachage pour C, de la bibliothèque standard C hcreate / hdestroy / hsearch, à celles de l' APR et de la glib , qui fournissent également des fonctions de hachage prédéfinies. Je recommande fortement de les utiliser plutôt que d'inventer votre propre table de hachage ou fonction de hachage; ils ont été fortement optimisés pour les cas d'utilisation courants.
Si votre jeu de données est statique, cependant, votre meilleure solution est probablement d'utiliser un hachage parfait . gperf générera un hachage parfait pour vous pour un ensemble de données donné.
la source
djb2 a 317 collisions pour ce dictionnaire anglais de 466k tandis que MurmurHash n'en a aucune pour les hachages 64 bits, et 21 pour les hachages 32 bits (environ 25 sont à prévoir pour les hachages 32 bits aléatoires de 466k). Ma recommandation est d'utiliser MurmurHash s'il est disponible, il est très rapide, car il prend plusieurs octets à la fois. Mais si vous avez besoin d'une fonction de hachage simple et courte à copier et coller dans votre projet, je vous recommande d'utiliser la version un octet à la fois de murmures:
La taille optimale d'une table de hachage est - en bref - aussi grande que possible tout en restant en mémoire. Parce que nous ne savons généralement pas ou ne voulons pas rechercher la quantité de mémoire disponible, et que cela pourrait même changer, la taille optimale de la table de hachage est environ 2 fois le nombre attendu d'éléments à stocker dans la table. Allouer beaucoup plus que cela rendra votre table de hachage plus rapide mais avec des rendements décroissants rapidement, ce qui rendra votre table de hachage plus petite que cela la rendra exponentiellement plus lente. C'est parce qu'il y a un compromis non linéaire entre la complexité spatiale et temporelle pour les tables de hachage, avec un facteur de charge optimal de 2-sqrt (2) = 0,58 ... apparemment.
la source
Premièrement, 40 collisions pour 130 mots hachés à 0..99 sont-ils mauvais? Vous ne pouvez pas vous attendre à un hachage parfait si vous ne prenez pas les mesures nécessaires pour que cela se produise. Une fonction de hachage ordinaire n'aura pas moins de collisions qu'un générateur aléatoire la plupart du temps.
Une fonction de hachage avec une bonne réputation est MurmurHash3 .
Enfin, en ce qui concerne la taille de la table de hachage, cela dépend vraiment du type de table de hachage que vous avez à l'esprit, en particulier, si les buckets sont extensibles ou à un emplacement. Si les buckets sont extensibles, il y a encore un choix: vous choisissez la longueur moyenne des buckets pour les contraintes mémoire / vitesse dont vous disposez.
la source
n - m * (1 - ((m-1)/m)^n) = 57.075...
. 40 collisions, c'est mieux que ce à quoi on pouvait s'attendre par hasard (46 à 70 pour un p-score de 0,999). La fonction de hachage en question est plus uniforme que si elle était aléatoire ou si nous assistons à un événement très rare.Bien que
djb2
, comme présenté sur stackoverflow par cnicutar , c'est presque certainement mieux, je pense que cela vaut la peine de montrer le K&R hachages aussi:1) Apparemment un algorithme de hachage terrible , tel que présenté dans la 1ère édition de K&R ( source )
2) Probablement un algorithme de hachage assez décent, tel que présenté dans K&R version 2 (vérifié par moi à la page 144 du livre); NB: assurez-vous de supprimer
% HASHSIZE
de l'instruction return si vous prévoyez de faire le dimensionnement du module à la longueur de votre tableau en dehors de l'algorithme de hachage. Aussi, je vous recommande de faire le retour et le type "hashval"unsigned long
au lieu du simpleunsigned
(int).Notez qu'il est clair d'après les deux algorithmes que l'une des raisons pour lesquelles le hachage de la 1ère édition est si terrible est qu'il ne prend PAS en compte l' ordre des caractères de la chaîne et
hash("ab")
qu'il renvoie donc la même valeur quehash("ba")
. Ce n'est cependant pas le cas avec le hachage de la 2e édition, qui renverrait (beaucoup mieux!) Deux valeurs différentes pour ces chaînes.Les fonctions de hachage GCC C ++ 11 utilisées pour
unordered_map
(un modèle de table de hachage) etunordered_set
(un modèle de jeu de hachage) semblent être les suivantes.Code:
la source
J'ai essayé ces fonctions de hachage et j'ai obtenu le résultat suivant. J'ai environ 960 ^ 3 entrées, chacune de 64 octets de long, 64 caractères dans un ordre différent, valeur de hachage 32 bits. Codes d' ici .
Une chose étrange est que presque toutes les fonctions de hachage ont un taux de collision de 6% pour mes données.
la source
Une chose que j'ai utilisée avec de bons résultats est la suivante (je ne sais pas si c'est déjà mentionné parce que je ne me souviens pas de son nom).
Vous précalculez un tableau T avec un nombre aléatoire pour chaque caractère de l'alphabet de votre clé [0,255]. Vous hachez votre clé 'k0 k1 k2 ... kN' en prenant T [k0] xor T [k1] xor ... xor T [kN]. Vous pouvez facilement montrer que c'est aussi aléatoire que votre générateur de nombres aléatoires et qu'il est très faisable sur le plan informatique et si vous rencontrez vraiment une très mauvaise instance avec beaucoup de collisions, vous pouvez simplement répéter le tout en utilisant un nouveau lot de nombres aléatoires.
la source