web-dev-qa-db-fra.com

Fonction de hachage pour une chaîne

Nous traitons actuellement la fonction de hachage dans ma classe. Notre instructeur nous a demandé une fonction de hachage sur Internet pour comparer aux deux que nous avons utilisées dans notre code.

Le premier:

int HashTable::hash (string Word)   
// POST: the index of entry is returned
{       int sum = 0;
        for (int k = 0; k < Word.length(); k++)
            sum = sum + int(Word[k]);
        return  sum % SIZE; 
}

Seconde:

int HashTable::hash (string Word)
{
   int seed = 131; 
   unsigned long hash = 0;
   for(int i = 0; i < Word.length(); i++)
   {
      hash = (hash * seed) + Word[i];
   }
   return hash % SIZE;
}

Où SIZE est 501 (la taille de la table de hachage) et l'entrée provient d'un fichier texte de plus de 20 000 mots.

J'ai vu this question avec quelques exemples de code mais je ne savais pas exactement quoi rechercher dans une fonction de hachage. Si je comprends bien, dans mon cas, un hachage prend une entrée (chaîne) et fait un calcul mathématique pour attribuer un numéro à la chaîne et l'insère dans un tableau. Ce processus est fait pour augmenter la vitesse de recherche dans la liste?

Si ma logique est bonne, quelqu'un a-t-il un bon exemple ou une ressource montrant une fonction de hachage différente qui implique une chaîne? Ou même le processus d'écriture de ma propre fonction de hachage efficace.

22
Nick

Premièrement, cela n'a généralement pas beaucoup d'importance dans la pratique. La plupart des fonctions de hachage sont "assez bonnes".

Mais si vous vous souciez vraiment, vous devez savoir que c'est un sujet de recherche en soi. Il y a des milliers d'articles à ce sujet. Vous pouvez toujours obtenir un doctorat aujourd'hui en étudiant et en concevant des algorithmes de hachage.

Votre deuxième fonction de hachage pourrait être légèrement meilleure, car elle devrait probablement séparer la chaîne "ab" à partir de la chaîne "ba". En revanche, elle est probablement moins rapide que la première fonction de hachage. Il peut ou non être pertinent pour votre candidature.

Je suppose que les fonctions de hachage utilisées pour les chaînes du génome sont assez différentes de celles utilisées pour hacher les noms de famille dans les bases de données téléphoniques. Peut-être même que certaines fonctions de hachage de chaîne conviennent mieux à l'allemand qu'aux mots anglais ou français.

De nombreuses bibliothèques de logiciels vous offrent des fonctions de hachage suffisamment bonnes, par exemple Qt a qhash , et C++ 11 a std :: hash in <functional>, Glib a plusieurs fonctions de hachage en C, et POCO a une fonction hachage .

J'ai assez souvent des fonctions de hachage impliquant des nombres premiers (voir identité de Bézout ) et xor, comme par exemple.

#define A 54059 /* a prime */
#define B 76963 /* another prime */
#define C 86969 /* yet another prime */
#define FIRSTH 37 /* also prime */
unsigned hash_str(const char* s)
{
   unsigned h = FIRSTH;
   while (*s) {
     h = (h * A) ^ (s[0] * B);
     s++;
   }
   return h; // or return h % C;
}

Mais je ne prétends pas être un expert du hachage. Bien sûr, les valeurs de A, B, C, FIRSTH devraient de préférence être des nombres premiers, mais vous auriez pu choisir d'autres nombres premiers.

Regardez une implémentation MD5 pour avoir une idée de ce que peuvent être les fonctions de hachage.

La plupart des bons livres sur l'algorithmique ont au moins un chapitre entier dédié au hachage. Commencez avec les pages de wiki sur fonction de hachage & table de hachage .

51

- La voie à suivre ces jours-ci -

Utilisez SipHash . Pour votre propre protection.

- Vieux et dangereux -

unsigned int RSHash(const std::string& str)
{
    unsigned int b    = 378551;
    unsigned int a    = 63689;
    unsigned int hash = 0;

    for(std::size_t i = 0; i < str.length(); i++)
    {
        hash = hash * a + str[i];
        a    = a * b;
    }

    return (hash & 0x7FFFFFFF);
 }

 unsigned int JSHash(const std::string& str)
 {
      unsigned int hash = 1315423911;

      for(std::size_t i = 0; i < str.length(); i++)
      {
          hash ^= ((hash << 5) + str[i] + (hash >> 2));
      }

      return (hash & 0x7FFFFFFF);
 }

Demandez à Google pour "fonction de hachage à usage général"

10
esskar

Les fonctions de hachage pour une utilisation algorithmique ont généralement 2 objectifs, d'abord elles doivent être rapides, ensuite elles doivent répartir uniformément les valeurs entre les nombres possibles. La fonction de hachage doit également fournir le même nombre pour la même valeur d'entrée.

si vos valeurs sont des chaînes, voici quelques exemples de mauvaises fonctions de hachage:

  1. string[0] - les caractères ASCII a-Z sont bien plus souvent que les autres
  2. string.lengh() - la valeur la plus probable est 1

De bonnes fonctions de hachage essaient d'utiliser chaque bit de l'entrée tout en minimisant le temps de calcul. Si vous n'avez besoin que de code de hachage, essayez de multiplier les octets par des nombres premiers et de les additionner.

3
Evan Dark

Utilisez boost :: hash

#include <boost\functional\hash.hpp>

...

std::string a = "ABCDE";
size_t b = boost::hash_value(a);
2
Denise Skidmore

Java String implémente hashCode comme ceci :

public int hashCode()

Returns a hash code for this string. The hash code for a String object is computed as

     s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

using int arithmetic, where s[i] is the ith character of the string, n is the length of the string, and ^ indicates exponentiation. (The hash value of the empty string is zero.) 

Donc quelque chose comme ça:

int HashTable::hash (string Word) {
    int result = 0;
    for(size_t i = 0; i < Word.length(); ++i) {
        result += Word[i] * pow(31, i);
    }
    return result;
}
1
Brendan Long