J'essaie de comprendre les tables de hachage - quelqu'un peut-il me l'expliquer - clairement?


25

Je veux comprendre l'utilisation et la mise en œuvre correctes des tables de hachage en php (désolé).

J'ai lu quelque part qu'un programmeur expérimenté avait créé une table de hachage, puis l'avait parcourue. Maintenant, je comprends pourquoi c'est mal mais je n'ai pas tout à fait la pleine connaissance pour savoir si ma compréhension est correcte (si vous voyez ce que je veux dire).

Alors, quelqu'un pourrait-il m'expliquer comment implémenter une table de hachage en php (probablement un tableau associatif) et peut-être plus important encore, comment accéder aux valeurs «avec un hachage» et ce que cela signifie réellement?

Réponses:


37

Présentation de la table de hachage simple

En guise de rappel, une table de hachage est un moyen de stocker une valeur sous une clé spécifique dans une structure de données. Par exemple, je pourrais stocker de la valeur "a"sous la clé 1, puis la récupérer plus tard en recherchant la clé 1dans la table de hachage.

L'exemple le plus simple d'une table de hachage à laquelle je peux penser du haut de ma tête est une table de hachage qui ne peut stocker que des entiers, où la clé de l'entrée de la table de hachage est également la valeur stockée. Disons que votre table est de taille 8, et c'est essentiellement un tableau en mémoire:

---------------------------------
|   |   |   |   |   |   |   |   |
---------------------------------
  0   1   2   3   4   5   6   7  

Fonction de hachage

Les fonctions de hachage vous donnent un index sur l'endroit où stocker votre valeur. Une fonction de hachage assez simple pour cette table serait d'ajouter 1 à la valeur que vous souhaitez stocker, puis de la modifier de 8 (la taille de la table). En d'autres termes, votre fonction de hachage est (n+1)%8, où nest l'entier que vous souhaitez stocker.

Inserts

Si vous souhaitez insérer une valeur dans cette table de hachage, vous appelez votre fonction de hachage (dans ce cas (n+1)%8) sur la valeur que vous souhaitez insérer pour vous donner un index. Par exemple, si nous voulons insérer 14, nous appelons (14 + 1) % 8et récupérons index 7, nous insérons donc la valeur dans index 7.

---------------------------------
|   |   |   |   |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

De même, nous pouvons insérer 33, 82 et 191 comme ceci:

---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

Collisions

Mais que se passe-t-il si nous essayons d'insérer quelque chose qui entrerait en collision avec une entrée? 2 devrait aller dans l'index 3, mais il est pris par 82. Il existe plusieurs façons de résoudre ce problème, la plus simple est d'appeler notre fonction de hachage à plusieurs reprises jusqu'à ce que nous trouvions un espace vide.

La logique est donc la suivante:

  1. (2 + 1)% 8 = 3
  2. L'index 3 est plein
  3. Rebranchez 3 dans notre fonction de hachage. ( 3 + 1)% 8 = 4 , qui est vide.
  4. Placez notre valeur dans l'index 4 .

Maintenant, la table de hachage ressemble à ceci, avec la valeur 2 stockée à l'index 4.

---------------------------------
|191|   |33 |82 |2  |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

L'inconvénient de cette solution est que très bientôt, notre table sera pleine! Si vous savez que la taille de vos données est limitée, cela ne devrait pas être un problème tant que votre table est suffisamment grande pour contenir toutes les valeurs possibles. Si vous voulez pouvoir en tenir plus, vous pouvez gérer les collisions différemment. Revenons à l'endroit où nous en étions avant d'insérer 2.

---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

Si vous vous souvenez, (2+1)%8donne-nous l'indice 3, qui est pris. Si vous ne voulez pas que votre table de hachage se remplisse, vous pouvez utiliser chaque index de table en tant que liste liée et l'ajouter à la liste à cet index. Ainsi, au lieu d'appeler à nouveau la fonction de hachage, nous ajouterons simplement à la liste à l'index 3:

            -----
            | 2 |
---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

Cette liste peut alors s'allonger autant que la mémoire le permet. Je peux insérer 18, et il sera simplement ajouté à 2:

            -----
            |18 |
            -----
            | 2 |
---------------------------------
|191|   |33 |82 |   |   |   |14 |
---------------------------------
  0   1   2   3   4   5   6   7  

Recherches

La recherche de valeurs dans votre table de hachage est rapide, étant donné que votre table de hachage est d'une taille assez grande. Vous appelez simplement votre fonction de hachage et obtenez l'index. Disons que vous voulez voir si 82 ​​est dans votre table. La fonction de recherche appelle (82+1)%8= 3et examine l'élément dans l'index 3et le renvoie pour vous. Si vous avez recherché 16, la fonction de recherche regarderait dans l'index 1et verrait qu'elle n'existe pas.

Les recherches doivent également gérer les collisions!

Si vous essayez de rechercher la valeur 2, votre table de hachage devra utiliser la même logique de collision utilisée pour stocker les données que pour récupérer les données. Selon le fonctionnement de votre table de hachage, vous devez soit hacher la clé à plusieurs reprises jusqu'à ce que vous trouviez l'entrée que vous recherchez (ou trouver un espace vide), soit vous parcourrez votre liste de liens jusqu'à ce que vous trouviez l'élément (ou arrivé à la fin de la liste)

Sommaire

Les tables de hachage sont donc un bon moyen de stocker et d'accéder rapidement aux paires clé-valeur. Dans cet exemple, nous avons utilisé la même clé que la valeur, mais dans les tables de hachage du monde réel, les clés ne sont pas si limitées. Les fonctions de hachage fonctionneront sur les clés pour générer un index, puis la clé / valeur peut être stockée dans cet index. Les tables de hachage ne sont pas vraiment destinées à être itérées, bien qu'il soit possible de le faire. Comme vous pouvez le voir, les tables de hachage peuvent avoir beaucoup d'espaces vides, et leur itération serait une perte de temps. Même si la table de hachage a une logique pour ignorer les recherches d'espace vide dans son itérateur, vous seriez mieux adapté en utilisant une structure de données conçue pour les itérateurs, comme les listes chaînées.


2
ASCII art FTW!
Anto

2
Très bonne réponse. Il peut être utile de mentionner que la méthode où chaque index est une liste chaînée est appelée chaînage.
alexn

+1 Excellente réponse, a surgi presque tous les doutes de ma tête. Besoin de poser une autre question. Chaque implémentation utilise-t-elle le hachage pour stocker des entiers? ou cela est utilisé pour des cas spécifiques? si oui, quels sont ces cas?
0 décimal0

@PHIfounder Je ne sais pas si j'ai bien compris votre question, mais la fonction de hachage qui est effectuée sur la clé est conçue pour être générique, pas seulement pour s'appliquer à un type de données spécifique tel que des entiers. Si nous parlons de code C, la table de hachage pourrait être conçue pour accepter (void *) pour la clé et la valeur et faire un calcul de hachage sur la valeur du pointeur de la clé.
Jeff

@Jeff en fait, je suis peut-être idiot de poser cette question, mais je parle de la structure interne d'un ordinateur; si chaque ordinateur utilise une structure de données comme une table de hachage pour stocker le magasin, faire référence à des entiers ou non en interne?
0 décimal0

7

Imaginez une bibliothèque avec des milliers de livres. Vous devez organiser les livres de manière à pouvoir les trouver par titre le plus rapidement possible.

Une façon (courante) de procéder consiste à trier les livres par ordre alphabétique. Si votre titre commence par dire "G", vous trouvez la zone "G", puis recherchez la deuxième lettre, dites "ö", puis "d", "e", "l", en affinant votre recherche, etc. , jusqu'à ce que vous trouviez le livre. Cependant, cela peut prendre du temps et, en outre, lorsque de nouveaux livres arrivent, vous devez parfois réorganiser votre mise en page pour faire de la place aux nouveaux arrivants.

C'est une recherche binaire. C'est bon.

Il existe cependant un moyen plus rapide de procéder. Supposons que vous énumériez toutes les bibliothèques et étagères, puis pour chaque livre, vous calculez un numéro spécial, espérons-le unique, qui correspond à une bibliothèque / étagère où le livre devrait être trouvé. La façon dont vous calculez la "clé" n'a pas d'importance tant qu'elle donne un nombre aléatoire. Par exemple, vous pouvez ajouter des codes de caractères de toutes les lettres du titre, puis les diviser par un nombre premier (peut-être pas la meilleure méthode, mais fonctionne quand même).

C'est du hachage. C'est beaucoup plus rapide, car vous n'avez pas besoin de parcourir des bibliothèques et des étagères entières en recherchant la lettre suivante dans le titre. Le hachage est généralement une opération à un coup, sauf si vous avez une «collision» lorsque deux livres ou plus se résolvent sur la même clé. Mais c'est bien, vous savez qu'ils se trouvent côte à côte et, selon la qualité de la fonction de hachage, il ne devrait pas y en avoir trop sous la même touche.

Les tables de hachage ont certaines limitations et caprices (rehachage / redimensionnement), ce qui maintient la recherche binaire comme un concurrent viable. Ce n'est pas tout noir et blanc en ce qui concerne la meilleure méthode. Mais c'est une autre histoire.

PS Désolé de ne pas avoir répondu directement à votre question (écrire une table de hachage en PHP), mais ce sont des détails et cela s'appelle "programmation";)


2
J'aime les explications non informatiques aux problèmes informatiques. +1
gablin

1

Pour autant que je sache, la table de hachage en PHP est simplement implémentée via:

$my_hash = array(
    1 => "Bob",
    2 => "Alice",
    3 => "Jack"
);

Vous accédez ensuite aux données via des appels tels que:

echo $my_hash[2]; // Will echo "Alice"

Vous utilisez la fonction foreach () pour parcourir le contenu du tableau.

La meilleure façon de comprendre les tables de hachage est de lire quelque chose comme http://en.wikipedia.org/wiki/Hash_table , mais en gros, cela se résume à ceci: le côté gauche de chaque ligne à l'intérieur de cet appel array () sont les clés . Ces clés seront soumises à un calcul de hachage et le résultat est un hachage. Vous avez probablement déjà vu des hachages MD5 ou SHA, cela ressemble assez à cela. Une partie spécifique de ce hachage, généralement les premiers caractères X mais parfois le hachage complet, sera utilisée pour identifier les soi-disant `` compartiments '', qui sont les zones de stockage des valeurs (le côté droit).

Ensuite, chaque fois que vous accédez à votre table de hachage, vous utilisez la clé pour obtenir la valeur. La clé est à nouveau calculée pour un hachage et le hachage est utilisé pour rechercher rapidement la valeur associée. Les tables de hachage permettent donc une recherche plus rapide que la simple recherche linéaire si tout a été simplement stocké. Le seul inconvénient est que certaines implémentations de hachage souffrent de collisions, ce qui est le même hachage calculé pour deux clés différentes. En général, ce n'est pas quelque chose dont vous devez vous inquiéter beaucoup.

J'espère que cela fournit un peu de contexte, mais veuillez essayer d'en savoir plus sur le sujet si cela vous intéresse. Mon explication est très rudimentaire et je suis sûr qu'il y a suffisamment de trous là-dedans, mais cela devrait suffire pour une explication rapide.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.