Aller au contenu

DS 6 (MP2I 2022-2023) — Table de hachage avec chaînage

Devoir surveillé · MP2I · 2022-2023 · partie 3 du DS 6 (4 h au total)

Cours : Tables de hachage

Autres parties : 1. Arbres n-aires en C · 2 et 4. Recherche trichotomique, médians

3. Table de hachage avec chaînage

On va réaliser dans cette partie une table de hachage avec chaînage pour gérer les collisions en OCaml.

On va utiliser ici la fonction Hashtbl.hash qui a le prototype suivant :

val hash : 'a -> int

et qui à toute valeur x va associer un entier strictement positif hash x. On a la garantie que si x = y alors hash x = hash y.

Ensemble

On considère le problème plus simple vu en classe consistant à représenter un ensemble fini de valeurs.

Question 13

Quelle relation entre ce problème et celui de la création d'un dictionnaire ?

Corrigé

Il suffit de rajouter des couples (clé,valeur) et de ne considérer que la clé pour le hachage.

On va réaliser ici une table de hachage où les cases contiennent des listes de valeurs pour gérer les collisions.

On considère donc le type suivant :

type 'a table = 'a list array

Question 14

Écrire une fonction

val contient : 'a table -> 'a -> bool

qui indique si un élément est dans la table.

Corrigé

L'entier hash x est quelconque : on le réduit modulo la taille de la table pour obtenir un indice valide.

let contient t x = List.mem x t.(hash x mod Array.length t)

Question 15

Écrire une fonction

val ajoute : 'a table -> 'a -> unit

qui rajoute un élément dans la table.

Corrigé
let ajoute t x =
  let h = hash x mod Array.length t in
  t.(h) <- x :: t.(h)

Dictionnaire

On considère ici le type précédent enrichi pour des dictionnaires associant des 'a à des 'b.

type ('a, 'b) dico = ('a * 'b) list array

On continue encore avec le même principe de chaînage en cas de collision mais on ne le fait que sur la première composante du couple.

Question 16

Écrire une fonction

val assoc : ('a * 'b) list -> 'a -> 'b

qui prend une liste de couples l et une valeur x et renvoie le premier y tel que (x,y) soit dans l.

Si l'élément n'est pas dedans, on fera une erreur.

Corrigé
let rec assoc l x =
  match l with
  | [] -> failwith "Non présent"
  | (y,v)::q ->
    if x = y
    then v
    else assoc q x

Question 17

En déduire une fonction

val dico_recherche : ('a, 'b) dico -> 'a -> 'b

qui prend un dico d et une valeur x et renvoie un y associé.

Corrigé
let dico_recherche d x = assoc d.(hash x mod Array.length d) x

Question 18

Quels sont les défauts de cette implémentation comparativement à l'adressage ouvert vu en TP ?

Corrigé

Le problème est la fragmentation mémoire induite par les listes chaînées. Sans mécanisme particulier, chaque collision risque d'engendrer des lenteurs d'accès mémoire qui sont évitées par un tableau qui peut tenir complètement dans le cache du processeur.