Une table de hachage ou un dictionnaire est une structure de données qui stocke des paires clé-valeur. L'avantage de la table de hachage est qu'à partir d'une clé, la recherche de la valeur correspondante est assez rapide. Pour simplifier, le temps nécessaire pour trouver une paire clé-valeur dans la table de hachage ne dépend pas de la taille de la table. Comparez cela au stockage des paires clé-valeur dans une liste ou un tableau. Pour trouver une paire clé-valeur, vous devez parcourir la liste depuis le début jusqu'à ce qu'une clé correspondante soit trouvée. Plus la liste est longue, plus il faut de temps pour trouver la paire clé-valeur. En utilisant la notation big-O, on peut dire que la recherche d'une clé dans une table de hachage est d'ordre O(1) alors que la recherche d'une clé dans une liste en utilisant la recherche linéaire est d'ordre O(N) (simplifié).
Pour insérer une paire clé-valeur dans la table de hachage, vous devez d'abord calculer le code de hachage de la clé. En .NET, tous les objets ont une méthode nommée GetHashCode
qui renvoie un code de hachage (entier de 32 bits) pour cet objet particulier. Il est important que des objets identiques renvoient le même code de hachage, mais il est également très utile que des objets différents renvoient des codes de hachage différents. Attention à l'idée fausse selon laquelle des objets différents ne peuvent pas renvoyer le même code de hachage. collision (voir ci-dessous).
Prenons l'exemple des codes de hachage de deux chaînes de caractères :
"Boo" 0x598FD95A
"Foo" 0x598FD8DE
Bien que les chaînes soient très similaires, elles ont des codes de hachage différents.
Je simplifie un peu les choses ici pour me concentrer sur les aspects importants d'une table de hachage. Dictionary<TKey, TValue>
stocke les paires clé-valeur dans un tableau. Pour localiser l'index de ce tableau où la paire clé-valeur sera stockée, vous devez calculer le code de hachage de la clé modulo la taille du tableau. Supposons que la taille du tableau soit de 5 :
Index("Boo") = 0x598FD95A % 5 = 4
Index("Foo") = 0x598FD8DE % 5 = 0
Il en résulte une table de hachage interne :
+---+---------+
| 0 | "Foo" |
+---+---------+
| 1 | (empty) |
+---+---------+
| 2 | (empty) |
+---+---------+
| 3 | (empty) |
+---+---------+
| 4 | "Boo" |
+---+---------+
La recherche d'une entrée dans la table de hachage est très rapide. Il suffit de calculer le code de hachage de la clé modulo la taille du tableau interne et de récupérer la chaîne à cet index.
Considérons maintenant la clé "Zoo" :
Index("Zoo") = 0x598FDC62 % 5 = 0
Elle a le même index que la clé "Foo". Il en résulte ce que l'on appelle un collision . Une implémentation correcte d'une table de hachage devra gérer les collisions et il existe des différentes stratégies pour y parvenir . En outre, au fur et à mesure que le tableau interne se remplit, il y aura de moins en moins d'éléments vides dans le tableau, ce qui entraînera un nombre croissant de collisions. Les facteur de charge est le rapport entre les éléments utilisés et le nombre total d'éléments dans le tableau interne. Dans l'exemple ci-dessus, le facteur de charge est de 2/5 = 0,4. La plupart des implémentations de tables de hachage augmentent la taille du tableau interne lorsque le facteur de charge dépasse un certain seuil.
Si vous souhaitez en savoir plus sur certains de ces concepts, vous devrez étudier certaines des ressources plus complètes mentionnées dans d'autres réponses.