TP 5 : Mémoïsation par tables de hachage
Judicaël Courant
∗Le 7 mai 2016
1 Temps de vol de la suite de Syracuse
On définit par récurrence la suite de Syracuse d’un entier N de la façon suivante : u0 =N et pour toutn∈N,un+1 =un/2si un est pair,un+1 = 3un+ 1siun est impair.
La conjecture de Syracuse affirme que pour tout N, il existe un entier n tel que un = 1. Elle n’a pas encore été démontré à ce jour. Le prolifique1 mathématicien Paul Erdős aurait dit à son propos « les mathématiques ne sont pas encore prêtes pour de tels problèmes ».
On appelletemps de vol d’un entierN, le plus petit entierntel queun= 1. On donne ci-dessous une table des temps de vol des premiers entiers :
N 1 2 3 4 5 6 7 8 9 10
temps de vol 0 1 7 2 5 8 16 3 19 6
Calculer, pour les entiers de[[1,107[[, le maximum de ces temps de vol. Vous essayerez d’une part avec un programme naïf et d’autre part avec une table de hachage pour mémoïser les résultats des calculs intermédiaires et vous comparerez les temps d’exécution (voir modulehashtbl).
À titre d’exemple, le temps de vol maximum des entiers de [[1,103[[ est 178, il est atteint pour 871.
2 Implantation de tables de hachage en Caml
2.1 Une table de nombres premiers
Les tables de hachage sont réputées mieux fonctionner si la taille du tableau utilisé est un nombre premier. On aura besoin essentiellement d’une table de nombres premiers proches de des puissances de 2. Pour cela, vous utiliserez la table donnée dans le fichier tp05-primes.ml à récupérer sur le site.
Le tableau t qui est défini dans ce fichier contient N = 40 éléments. Pour chaque entier i ∈ [[0, N[[,2i−t.(i) est premier et est de plus voisin de 2i.
Construire un tableauprimes : int vectdeN éléments tel que pour touti∈[[0, N[[,premiers.(i) contient2i−t.(i).
∗cbaCette œuvre est mise à disposition selon les termes de la Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International.
1. Environ 1525 articles publiés. . .
1
Option informatique MPSI La Martinière Monplaisir 2015-2016
2.2 Tables de hachage
On veut définir des tables de hachage en Caml. Un module pour faire cela existe déjà dans la bibliothèque standard (hashtbl) mais le but est d’apprendre vous-mêmes à les implanter.2
Pour cela, on utilisera la fonction de hachage hashtbl__hash: ’a -> int qui, à toute valeur Caml associe un entier. Cette fonction rend toujours le même entier pour une même valeur mais on peut considérer que cet entier est choisi de façon aléatoire et uniforme sur l’ensemble des entiers choisis par Caml.
Les tables de hachage seront définies comme suit : t y p e ( ’ a , ’ b ) t a b l e = {
m u t a b l e s i z e : int ; (* n o m b r e d ’ é l é m e n t s s t o c k é s *)
m u t a b l e i d a t a : int ; (* la t a i l l e de d a t a est t o u j o u r s p r i m e s .( i d a t a ) *) m u t a b l e d a t a : ( ’ a * ’ b ) l i s t v e c t ;
}
Une association (k, v) sera stockée dans la liste située à l’indice i du champ data, où i est le reste de (hashtbl k) dans la division par primes.(idata), taille du tableau donné dans le champdata.
Écrire des fonctions :
— create : unit -> (’a, ’b) tablecréant une table vide, dont le tableau de données a pour taille primes.(8).
— store : (’a, ’b) table -> ’a -> ’b -> unit tel que store t k v ajoute dans la table t l’association(k, v). Plus précisément,store t k vdoit ajouter(k, v)en tête de la liste située à l’indiceidanst, avecireste dehashtbl hash kdans la division parprimes.(t.idata) et augmenter de 1la valeur de t.size.
— find : (’a, ’b) table -> ’a -> ’btel que find t k retourne la valeur vassociée à la clé k dans la tablet. Si plusieurs valeurs ont été associées à la clék, on retournera la dernière mise.
— find_all : (’a, ’b) table -> ’a -> ’b list tel que find all t k retourne la liste des valeurs v associées à la clé kdans la table t. On retournera les valeurs dans l’ordre inverse de l’ordre où elles ont été entrées dans la table (i.e. la plus récente en tête de la liste, la dernière en fin de liste). Si aucune valeur n’est associée à la clék, on retournera la liste vide.
— resize : (’a, ’b) table -> unit redimensionnant la table : resize augmente la valeur du champ idata de la table t donnée en argument, remplaçant le vecteur t.data par un nouveau tableau de tailleprimes.(t.idata)et y recopiant les valeurs situées dans l’ancien vecteur.
— add : (’a, ’b) table -> ’a -> ’beffectuant la même chose que storemais regardant en- suite si le champ t.size de la table t donnée en argument est ou non plus grand que primes.(t.idata). S’il est strictement plus grand, appelle la fonction resize pour redimen- sionner la table.
— remove : (’a, ’b) table -> ’a tel que remove t k enlève la dernière liaison associée à k dans la table ts’il en existe une.
Note : pour obtenir un code plus concis et plus clair, il est conseillé d’utiliser les fonctionsassoc etdo list de la bibliothèque standard de Caml.
2. Si vous êtes à court d’idées, vous pouvez aller voir comment elles sont implantées mais attention : la repré- sentation choisie par la bibliothèque standard est un peu différente de la nôtre.
2