Hash Map
Dernière mise à jour
Une hash map stocke des paires clé-valeur et permet de rechercher une valeur par sa clé en O(1) en moyenne. Elle fonctionne exactement comme une table de hachage, mais chaque entrée de seau porte à la fois une clé et sa valeur associée. Pour stocker ou récupérer une paire, la clé est hachée vers un indice de seau, puis la chaîne de ce seau est parcourue à la recherche de la clé correspondante. Appuyez sur lecture ci-dessus pour voir les paires placées par seau haché et une valeur récupérée par sa clé.
C'est la structure derrière le dict de Python, le HashMap de Java et le Map/objets de JavaScript. Les collisions sont gérées de la même manière que dans une table de hachage - ici, par chaînage séparé - donc les performances dépendent d'une bonne fonction de hachage et d'un faible facteur de charge.
Complexité temporelle
| Opération | Moyenne | Pire cas |
|---|---|---|
| Insérer/mettre à jour (put) | O(1) | O(n) |
| Rechercher (get) | O(1) | O(n) |
| Supprimer | O(1) | O(n) |
| Espace | O(n) | O(n) |
La hash map dans les langages courants
| Langage | Type |
|---|---|
| Python | dict |
| Java | HashMap |
| JavaScript | Map / objet |
| C++ | std::unordered_map |
| Go | map |
Exemple résolu
Insertion des paires ("cat", 3), ("dog", 5), ("cat", 9), ("emu", 7) dans une map de 8 seaux, en utilisant hash(key) % 8. On suppose hash("cat") % 8 = 2, hash("dog") % 8 = 5, hash("emu") % 8 = 2 :
| Étape | Structure | Action |
|---|---|---|
Put ("cat", 3) | seau 2 : [("cat", 3)] | Hachée vers le seau 2 ; chaîne vide, donc la paire est ajoutée. |
Put ("dog", 5) | seau 2 : [("cat", 3)], seau 5 : [("dog", 5)] | Hachée vers le seau 5 ; chaîne vide, donc la paire est ajoutée. |
Put ("cat", 9) | seau 2 : [("cat", 9)], seau 5 : [("dog", 5)] | Hachée vers le seau 2 ; la clé "cat" est déjà dans la chaîne, donc sa valeur est mise à jour à 9. |
Put ("emu", 7) | seau 2 : [("cat", 9), ("emu", 7)], seau 5 : [("dog", 5)] | Hachée vers le seau 2 ; entre en collision avec "cat", la clé est introuvable, donc la paire est ajoutée. |
Get "emu" | seau 2 : [("cat", 9), ("emu", 7)] | Hachée vers le seau 2 ; la chaîne est parcourue, "cat" est ignorée, "emu" correspond, 7 est renvoyé. |
Quand utiliser une hash map
| À utiliser quand | À éviter quand |
|---|---|
Vous avez besoin d'une recherche, insertion et suppression en O(1) moyen par clé exacte. | Vous devez garder les clés triées ou faire des requêtes par plage - utilisez un BST équilibré ou une map triée. |
| Les clés sont hachables et l'égalité est bien définie (chaînes, entiers, tuples). | Les clés sont mutables et peuvent changer après insertion, ce qui corrompt leur seau. |
| Vous comptez, dédupliquez, mettez en cache ou indexez par un identifiant. | Vous avez besoin de garanties de pire cas O(log n) plutôt que de bornes moyennes amorties. |
| L'ordre d'itération n'a pas d'importance, ou une map ordonnée par insertion suffit. | La mémoire est très limitée - les seaux, la marge du facteur de charge et les pointeurs ajoutent du surcoût. |
Code de Hash Map
Une implémentation propre et exécutable de Hash Map en Python, JavaScript, Java, C++, C. Choisissez un langage, copiez le code ou ouvrez-le préchargé dans le Playground Coddy.
Code de Hash Map en Python
1# Python's built-in dict is a hash map: O(1) average2# insert, lookup, and delete.3inventory = {"apple": 3, "banana": 7}4
5# Insert and update6inventory["cherry"] = 57inventory["apple"] += 28
9# Lookup, with .get for a safe default on missing keys10print("apple: ", inventory["apple"])11print("mango: ", inventory.get("mango", 0))12
13# Membership test and delete14print("banana in stock:", "banana" in inventory)15del inventory["banana"]16print("banana in stock:", "banana" in inventory)17
18# Iterate over key-value pairs19for fruit, count in sorted(inventory.items()):20 print(f"{fruit}: {count}")21
22# Classic hash map use case: counting frequencies23words = "the quick brown fox jumps over the lazy dog the end".split()24freq = {}25for word in words:26 freq[word] = freq.get(word, 0) + 127
28print("Occurrences of the:", freq["the"])29print("Most common word: ", max(freq, key=freq.get))Code de Hash Map en JavaScript
1// The built-in Map is the idiomatic hash map in JavaScript:2// any key type, insertion-ordered iteration, O(1) average lookups.3const ages = new Map();4
5ages.set("Alice", 30);6ages.set("Bob", 25);7ages.set("Carol", 35);8ages.set("Bob", 26); // set on an existing key updates the value9
10console.log("Bob:", ages.get("Bob"));11console.log("Has Dave?", ages.has("Dave"));12console.log("Size:", ages.size);13
14ages.delete("Carol");15console.log("Size after delete:", ages.size);16
17for (const [name, age] of ages) {18 console.log(`${name} is ${age}`);19}20
21console.log("Keys:", [...ages.keys()].join(", "));Code de Hash Map en Java
1import java.util.HashMap;2import java.util.Map;3
4public class Main {5 public static void main(String[] args) {6 Map<String, Integer> ages = new HashMap<>();7 ages.put("Alice", 30);8 ages.put("Bob", 25);9 ages.put("Carol", 35);10
11 System.out.println("Bob -> " + ages.get("Bob"));12 System.out.println("contains Carol: " + ages.containsKey("Carol"));13 System.out.println("Dave or default: " + ages.getOrDefault("Dave", -1));14
15 // getOrDefault makes frequency counting a one-liner16 String[] words = {"apple", "banana", "apple", "cherry", "apple"};17 Map<String, Integer> counts = new HashMap<>();18 for (String w : words) {19 counts.put(w, counts.getOrDefault(w, 0) + 1);20 }21 System.out.println("apple count: " + counts.get("apple"));22
23 ages.remove("Bob");24 System.out.println("size after remove: " + ages.size());25
26 for (Map.Entry<String, Integer> entry : ages.entrySet()) {27 System.out.println(entry.getKey() + " is " + entry.getValue());28 }29 }30}Code de Hash Map en C++
1#include <algorithm>2#include <iostream>3#include <string>4#include <unordered_map>5#include <vector>6
7int main() {8 std::unordered_map<std::string, int> ages;9
10 // Insert and update11 ages["alice"] = 30; // operator[] inserts or overwrites12 ages.insert({"bob", 25}); // insert keeps an existing value13 ages.emplace("carol", 41);14 ages["alice"] = 31;15
16 // Lookup17 auto it = ages.find("bob");18 if (it != ages.end()) {19 std::cout << "bob is " << it->second << "\n";20 }21 std::cout << "has dave: " << ages.count("dave") << "\n";22
23 // Remove24 ages.erase("carol");25
26 // Iterate (sort keys first: unordered_map has no defined order)27 std::vector<std::string> keys;28 for (const auto& entry : ages) keys.push_back(entry.first);29 std::sort(keys.begin(), keys.end());30 for (const std::string& name : keys) {31 std::cout << name << " = " << ages[name] << "\n";32 }33 std::cout << "size: " << ages.size() << "\n";34 return 0;35}Code de Hash Map en C
1#include <stdbool.h>2#include <stdio.h>3#include <stdlib.h>4#include <string.h>5
6#define BUCKETS 167
8typedef struct Node {9 char key[24];10 int value;11 struct Node* next;12} Node;13
14// A small string -> int hash map with a reusable put/get/remove API15typedef struct {16 Node* buckets[BUCKETS];17 int size;18} HashMap;19
20unsigned int hashKey(const char* key) {21 unsigned int h = 5381;22 for (; *key; key++) h = h * 33 + (unsigned char)*key;23 return h % BUCKETS;24}25
26void mapPut(HashMap* map, const char* key, int value) {27 unsigned int i = hashKey(key);28 for (Node* n = map->buckets[i]; n != NULL; n = n->next) {29 if (strcmp(n->key, key) == 0) {30 n->value = value;31 return;32 }33 }34 Node* n = malloc(sizeof(Node));35 strcpy(n->key, key);36 n->value = value;37 n->next = map->buckets[i];38 map->buckets[i] = n;39 map->size++;40}41
42bool mapGet(const HashMap* map, const char* key, int* out) {43 for (Node* n = map->buckets[hashKey(key)]; n != NULL; n = n->next) {44 if (strcmp(n->key, key) == 0) {45 *out = n->value;46 return true;47 }48 }49 return false;50}51
52void mapRemove(HashMap* map, const char* key) {53 Node** link = &map->buckets[hashKey(key)];54 while (*link != NULL) {55 if (strcmp((*link)->key, key) == 0) {56 Node* old = *link;57 *link = old->next;58 free(old);59 map->size--;60 return;61 }62 link = &(*link)->next;63 }64}65
66int main(void) {67 HashMap map = {0};68 mapPut(&map, "alice", 30);69 mapPut(&map, "bob", 25);70 mapPut(&map, "carol", 41);71 mapPut(&map, "alice", 31); // updates the existing key72 int age;73 if (mapGet(&map, "bob", &age)) printf("bob is %d\n", age);74 printf("has dave: %s\n", mapGet(&map, "dave", &age) ? "yes" : "no");75 mapRemove(&map, "carol");76 printf("size: %d\n", map.size);77 return 0;78}FAQ sur la hash map
Quelle est la différence entre une hash map et une table de hachage ?
Quelle est la complexité temporelle d'une hash map ?
O(1) en moyenne avec une bonne fonction de hachage et un faible facteur de charge. Dans le cas pathologique où toutes les clés entrent en collision dans un seul seau, ils dégénèrent en O(n), c'est pourquoi le redimensionnement et un bon hachage sont importants.Comment une hash map gère-t-elle deux clés qui se hachent vers le même seau ?
Hash map ou arbre binaire de recherche : lequel choisir ?
O(1) moyen. Utilisez un arbre binaire de recherche équilibré (comme TreeMap ou std::map) lorsque vous avez besoin de clés triées, de requêtes par plage ou de recherches de prédécesseur/successeur, qui coûtent O(log n). Le BST échange un peu de vitesse contre des garanties d'ordre qu'une hash map ne peut pas offrir.Qu'est-ce que le facteur de charge et pourquoi déclenche-t-il le redimensionnement ?
0.75. Le redimensionnement est en O(n) mais rare, donc il est amorti et maintient les opérations moyennes en O(1).Puis-je utiliser un objet mutable comme une liste comme clé de hash map ?
TypeError: unhashable type pour une list, par exemple. Si vous mutez une clé après l'avoir insérée, son hachage change et la map ne peut plus la trouver dans le bon seau, perdant silencieusement l'entrée. Utilisez des clés immuables comme des chaînes, des nombres ou des tuples.