Académique Documents
Professionnel Documents
Culture Documents
Eric Gaussier
1. Fonctions de hachage
2. Chainage séparé
3. Test linéaire
4. Hachage double
5. Hachage dynamique
Exemple
16838 57 38 6
5758 35 58 58
25566 55 66 0
26966 0 66 65
12767 60 67 90
11367 18 67 25
Fonctions utilisées
◮ k%97 (gauche)
◮ k%100 (centre)
◮ ((int)(α ∗ k))%100 (droite)
+111 ∗ 1285 + 110 ∗ 1284 + 103 ∗ 1283 + 107 ∗ 1282 + 101 ∗ 128 + 121
((((((((((97∗128+118)∗128+101)∗128+114)∗128+121)∗128+108)
∗128+111)∗128+110)∗128+103)∗128+107)∗128+101)∗128+121
Algorithme associé :
static int hash(String s, int M) {
int h = 0, a = 127 ;
for (int i = 0 ; i < s.length() ; i++)
h = (a*h + s.charAt(i)) % M ;
return h ;
}
Question :
Que se passe-t-il lorsque la taille de la table est un multiple de
127 ?
Propriétés
1. Le chaı̂nage séparé réduit le nombre de comparaisons pour la
recherche séquentielle d’un facteur M en moyenne (M listes
chaı̂nées au lieu d’une), en requérant un espace mémoire
supplémentaire pour M liens.
2. Dans une table de hachage avec chaı̂nage séparé sur M listes
pour N clés (et pour peu que la fonction de hachage soit bien
N
définie), la longueur moyenne des listes est M (la probabilité
N
pour que le nombre de clés dans chaque liste soit M est à peu
près 1).
Test linéaire
Cas où l’on connaı̂t à l’avance le nombre d’éléments à placer dans
la table et où l’on dispose d’un emplacement mémoire contigu
permettant de stocker toutes les clés en laissant un peu d’espace
libre : placer N éléments dans une table de taille M > N (hachage
ouvert)
Principe
◮ Hacher la clé
◮ Si collision, on teste la place suivante de la table
◮ Si elle libre, on y range la clé
◮ On continue sinon
Test linéaire
1 1 1 1
(1 + ) ; (1 + )
2 1−α 2 (1 − α)2
Hachage double
Hachage double
Hachage dynamique
Principe
◮ Dès que plus de la moitié de la table de hachage est remplie,
on double sa taille
◮ On utilise ensuite un chaı̂nage séparé, un test linéaire ou un
chaı̂nage double
Exemple
A S E R C H I N G X M P L
7 3 9 9 8 4 11 7 10 12 0 8 6
1 3 1 5 5 5 3 3 2 3 5 4 2
◮ Comment se déroule un test linéaire (1ière et 2ième lignes)
sur ces données ?
◮ Et un chaı̂nage double (1ière, 2ième et 3ième lignes) ?
Les algorithmes que nous allons voir examinent les clés par
morceaux au lieu de comparer leur totalité. On parle alors de
méthodes de recherche radix.
Ces méthodes sont utiles lorsqu’il est facile d’accéder à des parties
de clé.
Méthode search
private ITEM searchR(Node h, KEY v, int i) {
if (h == null) return null ;
if (equals(v,h.item.key)) return h.item ;
if (bit(v,i) == 0)
return searchR(h.l, v, i+1) ;
else return searchR(h.r, v, i+1) ;
}
ITEM search(KEY key) {
return searchR(head, key, 0) ;
}
Remarques Longueur des clés (préfixe) ; clés dupliquées
Problèmes
1. Les branchements unaires conduisent à la création de n ?uds
supplémentaires
2. Le fait d’avoir 2 types de n ?uds entraı̂ne des complications
Illustration au tableau
Méthode search
private ITEM searchR(Node h, KEY v, int i) {
if (h.bit ≤ i) return h.item ;
if (bit(v,h.bit) == 0)
return searchR(h.l, v, h.bit) ;
else return searchR(h.r, v, h.bit) ;
}
ITEM search(KEY key) {
ITEM t = searchR(head, key, 0) ;
if (t == null) return null ;
if (equals(t.key,key)) return t ;
return null ;
}
Remarques Longueur des clés (préfixe) ; clés dupliquées
Méthode insert
Pour insérer une clé, on commence par une recherche. La méthode
précédente renvoie la seule clé de l’arbre qui doit être distinguée de
la clé à insérer. On détermine alors la position du premier bit sur
lequel les clés diffèrent, puis on compare ce bit à celui des n ?uds
du chemin de recherche.
Si on arrive sur un n ?ud spécifiant une position supérieure, on sait
qu’on a sauté un bit dans la recherche qui aurait conduit à un lien
null dans un trie classique. On ajoute alors un nouveau n ?ud
testant le bit. Si l’on ne rencontre pas un tel n ?ud, on se trouve
dans un cas correspondant à une recherche se terminant sur une
feuille dans un trie classique. On crée alors un nouveau n ?ud qui
distingue la clé de recherche de la clé ayant terminé la recherche.
Méthode insert
Par convention, le lien le plus à gauche (qui correspond à la clé
dont tous les bits sont à 0) ne référence aucun n ?ud interne (seule
la clé nulle a tous ses bits à 0).
void insert(ITEM x) {
int i = 0 ;
KEY v = x.key() ;
ITEM t = searchR(head.l, v, -1) ;
KEY w = (t == null) ? null : t.key() ;
if (v == w) return ;
while (bit(v,i) == bit(w,i)) i++ ;
head.l = insertR(head.l, x, i, head) ;
}
Méthode insert
private Node insertR(Node h, ITEM x, int i, Node p) {
KEY v = x.key() ;
if ((h.bit ≥ i) || (h.bit ≤ p.bit)) {
Node t = new Node(x,i) ;
t.l = bit(v,t.bit) == 0 ? t : h ;
t.r = bit(v,t.bit) == 0 ? h : t ;
return t ;
}
if (bit(v,h.bit) == 0)
h.l = insertR(h.l,x,i,h) ;
else h.r = insertR(h.r,x,i,h) ;
return h ;
}
N A T P
1250 3 4 3
2500 7 6 5
5000 15 12 11
25000 115 87 80
200000 1579 1012 945
Méthode search
private boolean searchR(Node h, char[] s, int i) {
if (h == null) return false ;
if (i == s.length) return h.c = END ;
if (s[i] < h.c) return searchR(h.l, s, i) ;
if (s[i] > h.c) return searchR(h.r, s, i) ;
return searchR(h.m, s, i+1) ;
}
boolean search(String s) {
return searchR(head, s.toCharArray(), 0) ;
}
Remarques Longueur des clés (préfixe) ; clés dupliquées
Méthode insert
private Node insertR(Node h, char[] s, int i) {
char ch = (i < s.length) ? s[i] : END ;
if (h == null) { h = new Node() ; h.c = ch ; }
if (ch == END && h.c == END) return h ;
if (s[i] < h.c) h.l = insertR(h.l, s, i) ;
if (s[i] == h.c) h.m = insertR(h.m, s, i) ;
if (s[i] > h.c) h.r = insertR(h.r, s, i) ;
return h ;
}
boolean insert(String s) {
head = insertR(head, s.toCharArray(), 0) ;
}