148 votes

fonction de hachage pour une chaîne de caractères

Je travaille sur une table de hachage en langage C et je teste la fonction de hachage pour les chaînes de caractères.

La première fonction que j'ai essayée est d'ajouter du code ascii et d'utiliser le modulo (%100) mais j'ai obtenu 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 (il s'agit d'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 la suivante : quel est le meilleur algorithme pour hacher une chaîne de caractères ? et comment déterminer la taille de la table de hachage ?

Merci d'avance !

-)

11 votes

Si votre table de hachage a 10K entrées, pourquoi utiliseriez-vous le modulo 100 ? Obtenir 40 collisions sur 130 mots n'est pas surprenant avec un si petit modulo.

0 votes

Il existe de nombreuses implémentations de hachage de chaînes de caractères disponibles sur Google et SO (lire : il faut continuer à chercher). De nombreuses approches utilisent un "barrel shift" ou un "rolling" hash (éventuellement avec des phases de "mixing") -- mais tenez compte de Gregory !

14 votes

Ver burtleburtle.net/bob/hash/evahash.html y partow.net/programmation/hashfunctions pour lequel on trouve des ressources sur les différents hachages (du général au cryptographique en passant par les chaînes).

227voto

cnicutar Points 98451

J'ai eu de bons résultats avec djb2 par Dan Bernstein.

unsigned long
hash(unsigned char *str)
{
    unsigned long hash = 5381;
    int c;

    while (c = *str++)
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

    return hash;
}

48 votes

La page liée dans la réponse est très intéressante.

2 votes

Comment le programme sort de la boucle while ?? =S

4 votes

@danfly09 Quand c est zéro. L'équivalent de while(c = *str++) serait (0 != (c = *str++))

28voto

Jerry Coffin Points 237758

D'abord, vous faites généralement no vous voulez utiliser un hachage cryptographique pour une table de hachage. Un algorithme qui très rapide selon les normes cryptographiques est toujours atrocement lent selon les normes des tables de hachage.

Deuxièmement, vous voulez vous assurer que chaque élément de l'entrée peut/va affecter le résultat. Un moyen simple d'y parvenir est de faire tourner le résultat actuel d'un certain nombre de bits, puis de faire un XOR du code de hachage actuel avec l'octet actuel. Répétez l'opération jusqu'à ce que vous atteigniez la fin de la chaîne. Notez que vous faites généralement no Je ne veux pas non plus que la rotation soit un multiple pair de la taille de l'octet.

Par exemple, dans le cas courant d'octets de 8 bits, vous pouvez effectuer une rotation de 5 bits :

int hash(char const *input) { 
    int result = 0x55555555;

    while (*input) { 
        result ^= *input++;
        result = rol(result, 5);
    }
}

Edit : Notez également que 10000 slots est rarement un bon choix pour la taille d'une table de hachage. En général, vous souhaitez deux choses : soit un nombre premier comme taille (nécessaire pour garantir la correction avec certains types de résolution de hachage), soit une puissance de 2 (afin que la réduction de la valeur à la plage correcte puisse être effectuée avec un simple masque de bits).

0 votes

Ce n'est pas c, mais je serais intéressé par vos réflexions sur cette réponse connexe : stackoverflow.com/a/31440118/3681880

1 votes

@Suragch : Depuis que j'ai écrit ceci, un certain nombre de processeurs ont commencé à inclure du matériel spécial pour accélérer le calcul du SHA, ce qui l'a rendu beaucoup plus compétitif. Cela dit, je doute que votre code soit aussi sûr que vous le pensez - par exemple, les nombres à virgule flottante IEEE ont deux modèles de bits différents (0 et -0) qui devraient produire les mêmes hachages (ils seront comparés comme égaux l'un à l'autre).

0 votes

@Jerry Coffin de quelle bibliothèque ai-je besoin pour la fonction rol() ?

10voto

RushPL Points 1979

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.

uint32_t jenkins_one_at_a_time_hash(char *key, size_t len)
{
    uint32_t hash, i;
    for(hash = i = 0; i < len; ++i)
    {
        hash += key[i];
        hash += (hash << 10);
        hash ^= (hash >> 6);
    }
    hash += (hash << 3);
    hash ^= (hash >> 11);
    hash += (hash << 15);
    return hash;
}

9voto

Nick Johnson Points 79909

Il existe un certain nombre d'implémentations de tables de hachage pour le langage C, depuis la bibliothèque standard hcreate/hdestroy/hsearch, jusqu'à celles de l'application APR y glib qui fournissent également des fonctions de hachage préconstruites. Je vous recommande vivement de les utiliser plutôt que d'inventer votre propre table de hachage ou fonction de hachage ; elles ont été fortement optimisées pour les cas d'utilisation courants.

Toutefois, si votre ensemble de données est statique, la meilleure solution est probablement d'utiliser un fichier de type hachis parfait . gperf générera pour vous un hachage parfait pour un ensemble de données donné.

0 votes

Hsearch recherche en comparant les chaînes de caractères ou l'adresse de la chaîne de caractères ? Je pense qu'il vérifie juste l'adresse du ptr ? J'ai essayé d'utiliser différents pointeurs mais la même chaîne de caractères. hsearch échoue en déclarant qu'aucun élément n'a été trouvé.

2voto

Pascal Cuoq Points 39606

Tout d'abord, 40 collisions pour 130 mots hachés à 0..99 est-il mauvais ? Vous ne pouvez pas vous attendre à un hachage parfait si vous ne prenez pas de mesures spécifiques pour qu'il 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 ayant 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 en tête, notamment si les buckets sont extensibles ou à un seul emplacement. Si les buckets sont extensibles, là encore, il y a un choix à faire : vous choisissez la longueur moyenne du bucket en fonction des contraintes de mémoire et de vitesse que vous avez.

1 votes

Le nombre attendu de collisions de hachage est n - m * (1 - ((m-1)/m)^n) = 57.075... . 40 collisions est meilleur que ce à quoi on pourrait s'attendre par hasard (46 à 70 avec un score p de 0,999). La fonction de hachage en question est plus uniforme que si elle était aléatoire ou si nous étions témoins d'un événement très rare.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X