Vous êtes sur la page 1sur 9

TP1 : Structure de données : le dictionnaire

V1

Table des matières

I Présentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
II Le type dict en Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
II.1 Déclaration littérale . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
II.2 Lecture de valeur, ajout de clef et modification de valeur . . . . . . . . 1
II.3 Suppression d’une clef . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
II.4 Itérations sur les clefs et les valeurs . . . . . . . . . . . . . . . . . . . . 2
II.5 Test d’appartenance avec le mot clef in . . . . . . . . . . . . . . . . . 2
II.6 Copie d’un dictionnaire . . . . . . . . . . . . . . . . . . . . . . . . . . 2
II.7 Restriction sur les clefs et les valeurs . . . . . . . . . . . . . . . . . . . 3
III Exercices sur les dictionnaires . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
III.1 Exercice 1 : QCM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
III.2 Exercice 2 : notation d’un QCM . . . . . . . . . . . . . . . . . . . . . 4
III.3 Exercice 3 : Fréquence d’apparition des lettres dans un texte . . . . . 4
IV Fonctionnement interne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
IV.1 Généralités . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
IV.2 Fonction de hashage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
IV.3 Collision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
IV.4 Résolution des collisions par chaı̂nage . . . . . . . . . . . . . . . . . . 6
IV.5 Exercice 4 : Hashage et Collisions . . . . . . . . . . . . . . . . . . . . . 8

1
Informatique commune PSI

I Présentation
En informatique, un tableau associatif (aussi appelé dictionnaire ou table d’association est un type
de données associant à un ensemble de clefs, un ensemble correspondant de valeurs. Chaque clef est
associée à une seule valeur (au plus). On peut citer par exemple :
— annuaire : les noms sont les clés et les valeurs sont les numéros de téléphone et les adresses ;
— dictionnaire : les mots sont les clés et les définitions sont les valeurs ;
— inventaire : les produits sont les clés et les quantités sont les valeurs.

II Le type dict en Python


C’est une structure muable (comme les listes) et itérable.

II.1 Déclaration littérale


Pour déclarer un dictionnaire vide, on a la choix entre les accolades {} et la fonction dict().

1 >>> d1 = {} ; d2 = dict ()
2 >>> type ( d1 ) ; type ( d2 )
3 < class ’ dict ’ >
4 < class ’ dict ’ >

Si on souhaite directement avoir un tableau rempli, le format est le suivant : {clef1: valeur1,
clef2: valeur2, ... }.

1 >>> lettres = { ’m ’: 1 , ’s ’: 4 , ’p ’: 2 , ’i ’: 4}
2 >>> lettres
3 { ’m ’: 1 , ’s ’: 4 , ’p ’: 2 , ’i ’: 4}
4 >>> type ( lettres )
5 < class ’ dict ’ >

II.2 Lecture de valeur, ajout de clef et modification de valeur


Le format pour traiter ces 3 cas est le même : d[clef].

1 >>> lettres = { ’m ’: 1 , ’s ’: 4 , ’p ’: 2}
2 >>> lettres [ ’i ’] = 4 # création d’un nouveau couple clef, valeur dans lettres
3 >>> lettres [ ’m ’] # accès en lecture de la valeur correspondant à la clef ’m’
4 1
5 >>> lettres [ ’s ’] = 2 # changement de la valeur correspondant à la clef ’s’
6 >>> print ( lettres )
7 { ’m ’: 1 , ’s ’: 2 , ’p ’: 2 , ’i ’: 4}

II.3 Suppression d’une clef


Comme pour une liste, on utilise le mot clé del :

www.upsti.fr 1/8
Informatique commune PSI

1 >>> print ( lettres )


2 { ’m ’: 1 , ’s ’: 2 , ’p ’: 2 , ’i ’: 4}
3 >>> lettres = { ’m ’: 1 , ’s ’: 4 , ’p ’: 2 , ’i ’: 4 , ’o ’: 2}
4 >>> del lettres [ ’o ’]
5 >>> print ( lettres )
6 { ’m ’: 1 , ’s ’: 4 , ’p ’: 2 , ’i ’: 4}

II.4 Itérations sur les clefs et les valeurs


Dans une boucle for, on peut directement itérer sur les clés, sur les valeurs ou sur les deux à la fois.

1 >>> for clef in lettres . keys ():


2 ... print ( clef )
3 m
4 s
5 p
6 i
7 >>> for valeur in lettres . values ():
8 ... print ( valeur )
9 1
10 4
11 2
12 4
13 >>> for cle , val in lettres . items ():
14 ... print ( cle , val )
15 m 1
16 s 4
17 p 2
18 i 4

II.5 Test d’appartenance avec le mot clef in


On peut tester si une clef apparaı̂t dans un dictionnaire grâce au test cle in dico.

1 >>> ’k ’ in lettres
2 False
3 >>> ’i ’ in lettres
4 True

II.6 Copie d’un dictionnaire


Comme pour les listes, on a une méthode d.copy(). On rappelle que la commande d’affectation d2 =
d1 ne crée pas une copie valide, mais juste donne 2 noms différents à un même objet, ce qui est très
rarement ce qui est souhaité.

1 >>> d1 = { ’m ’: 1 , ’s ’: 4 , ’p ’: 2 , ’i ’: 4}
2 >>> d2 = d1 ; d3 = d1 . copy ()
3 >>> d1 [ ’m ’] = 0 ; d2 [ ’o ’] = 2
4 >>> print ( d1 ) ; print ( d2 ) ; print ( d3 )
5 { ’m ’: 0 , ’s ’: 4 , ’p ’: 2 , ’i ’: 4 , ’o ’: 2}
6 { ’m ’: 0 , ’s ’: 4 , ’p ’: 2 , ’i ’: 4 , ’o ’: 2}
7 { ’m ’: 1 , ’s ’: 4 , ’p ’: 2 , ’i ’: 4}

www.upsti.fr 2/8
Informatique commune PSI

II.7 Restriction sur les clefs et les valeurs


Il n’y a pas de restriction sur les valeurs, mais il existe une restriction sur les clefs : il faut qu’elles
soient strictement immuables (ne pas être ou contenir de listes ou de dictionnaire par exemple). Les
principaux types de clefs qui sont pratiques à utiliser sont :
— les chaines de caractères ;
— les entiers ;
— les n-uplets comprenant des chaines de caractères et/ou des entiers.

III Exercices sur les dictionnaires


III.1 Exercice 1 : QCM
Question 1 : Pour déclarer un dictionnaire, on peut utiliser les commandes :
A) mon_dict=()
B) mon_dict={}
C) mon_dict=dict()
D) mon_dict=[]
Question 2 : Pour le dictionnaire mon_dic={1:’A’,2:’B’}
A) 1 représente une valeur
B) 1 représente un indice
C) 1 représente une clé
D) 1 est un numéro de ligne
Question 3 : Pour le dictionnaire mon_dic={1:’A’,2:’B’}
A) ‘A’ représente une valeur
B) ‘A’ représente un indice
C) ‘A’ représente une clé
D) ‘A’ est un numéro de ligne
Question 4 : Dans un dictionnaire
A) les clés sont uniques
B) les clés et les valeurs sont uniques
C) les valeurs sont uniques
D) les clés et les valeurs ne sont pas uniques
Question 5 : Pour savoir si un élément est une clé d’un dictionnaire, on peut utiliser
la méthode
A) cle in mon_dic.values()
B) cle in mon_dic.keys()
C) cle in values(mon_dic)
D) cle in keys(mon_dic)
Question 6 : Pour savoir si un élément est une valeur d’un dictionnaire, on peut utiliser
la méthode
A) val in mon_dic.values()
B) val in mon_dic.keys()
C) val in values(mon_dic)
D) val in keys(mon_dic)
Question 7 : Pour affecter une valeur à une clé dans un dictionnaire, on utilise la
méthode

www.upsti.fr 3/8
Informatique commune PSI

A) mon_dict[cle] = valeur
B) mon_dict(cle) = valeur
C) mon_dict[valeur] = cle
D) mon_dict.append(cle,valeur)
Question 8 : Pour effacer une clé et sa valeur, on utilise
A) del(mon_dic[cle])
B) mon_dic.del(valeur)
C) del(mon_dic,valeur)
D) del(mon_dic[valeur])
Question 9 : Pour parcourir les clés d’un dictionnaire, on utilise
A) for cle in mon_dic.keys()
B) for cle in range(len(mon_dic))
C) for cle in mon_dic.values()
D) for val in mon_dic.values()
Question 10 : Pour parcourir les valeurs d’un dictionnaire, on utilise
A) for val in mon_dic.keys()
B) for cle in range(len(mon_dic))
C) for cle in mon_dic.values()
D) for val in mon_dic.values()

III.2 Exercice 2 : notation d’un QCM


Les réponses valables d’un QCM et les réponses d’une candidate sont stockées sous la forme de dic-
tionnaires. Ecrire une fonction score(dic candidat, dic reponses) qui évalue le score selon le principe :
— une bonne réponse vaut 3 points,
— une mauvaise réponse vaut -1 points,
— une absence de réponse vaut 0 points.
Lorsque le candidat n’a pas répondu à la question, celle-ci n’est pas présente dans son dictionnaire de
réponses.

III.3 Exercice 3 : Fréquence d’apparition des lettres dans un texte


Il s’agit d’écrire trois fonctions permettant d’étudier la fréquence d’apparition des caractères dans un
texte ( méthode préalable pour crypter ou décrypter un texte ). La fonction f requence la plus grande
fera appel au dictionnaire crée par la fonction f requence caracteres. La fonction caracteres plus f requents
fera appel aux deux fonctions précédentes. Les fonctions doivent répondre à leur docstring !

IV Fonctionnement interne
IV.1 Généralités
Bien évidemment, on souhaite avoir la rapidité en même temps que la souplesse d’utilisation. Pour
cela, un dictionnaire est organisé en interne de la manière suivante :
— on garde une structure indicée comme une liste ou un tableau, ce qui garantit un temps d’accès
à une valeur quelconque en temps constant (en O(1)) ;
— on a besoin d’une fonction dont le rôle est de calculer un indice sur la base de la clé. Cette fonction
est appelée fonction de hashage. On la notera h dans la suite du cours telle que h : K → N.

www.upsti.fr 4/8
Informatique commune PSI

Tableau contenant
Ensemble des clés
les valeurs associées

h(k2 )

h(k3 )

k1

k0
h(k4 )

h(k1 )
k4 k2
h(k0 )
k3

Figure 1 – Schéma représentant les liens entre l’ensemble des clés et les indices d’un tableau grâce à
la fonction de hashage.

Elle calcule l’indice correspondant à la clé en un temps très court pour ne pas dégrader les
performances des primitives (un exemple très simple est exposé plus loin).
Une représentation du fonctionnement vous est fournie à la figure 1. Les clés sont notées kn avec
n ∈ N. La fonction de hachage calcule un indice h(kn ) de type entier ce qui permet de faire le lien
(matérialisé par une flèche) entre une clé et un indice du tableau, Dans la suite, et pour simplifier
notre exemple, nous partons avec des clés de type chaı̂ne de caractères et des valeurs de type entier
(à ne pas confondre avec les indices du tableau qui sont aussi des entiers). La structure pour stocker
les paires clé-valeur sera un tableau. En suivant la syntaxe python, notre dictionnaire aura l’allure
suivante : {"key20":45 , "key31":2678 , "key2":954 , "key17":4269 , "key58":329}.

www.upsti.fr 5/8
Informatique commune PSI

1 def h ( chaine , n ):
2 s =0
3 for c in chaine :
4 s += ord ( c ) # ord() est la fonction ascii() définie auparavant.
5 # elle est présente nativement dans python.
6 return s % n

Figure 2 – Code python d’une fonction de hachage

IV.2 Fonction de hashage


Comme mentionné précédemment, la fonction de hachage permet de calculer un entier à partir d’une
clé quelconque. Plusieurs solutions pour assurer cette tâche sont envisageables mais cela sort du cadre
de ce court. Dans l’idéal cette fonction doit :
— calculer en un temps très court ;
— être injective, c’est à dire fournir une valeur différente pour chaque clé.
Dans notre exemple, on peut simplement utiliser une fonction opérant la somme du code ASCII de
chaque caractère constituant la clé et renvoyant le reste de la division entière entre cette somme et
la taille du tableau. On est ainsi assuré de toujours obtenir une valeur entre 0 et l’indice maximal
disponible. Formellement cela donne :

h: K → VP 
n−1
c 7→ i=0 ascii(ci ) mod n

avec c une chaı̂ne de caractères, ci le caractère d’indice i de c et ascii() une fonction prenant un
caractère et retournant son code ASCII. Le code python d’une telle fonction est donnée à la figure 2.
Pour l’exemple donné plus haut avec un tableau de sept éléments, cela donne la représentation de la
figure 3.

IV.3 Collision
Dans notre exemple avec des clés de type chaı̂ne de caractères, l’ensemble est de cardinal infini. De
l’autre côté, le tableau possède un nombre fini d’indices. La fonction ne peut donc être injective. Quelle
que soit la taille de ce tableau, il y a forcément au moins un cas où pour deux clés différentes, la fonction
de hachage produira le même entier. Dans ce cas, on dit qu’il y a collision. Un exemple est représenté
à la figure 4 en ajoutant deux nouvelles paires clé-valeur à notre dictionnaire exemple (les deux
dernières). Nous avons maintenant {"key20":45 , "key31":2678 , "key2":954 , "key17":4269
, "key58":329 , "key33":97 }. Les clés "key58" et "key33" comme paramètre de la fonction h
donnent le même entier.

IV.4 Résolution des collisions par chaı̂nage


Une des solutions en cas de collision est le chaı̂nage. L’idée consiste à placer les paires clé-valeur à
l’indice désigné par la fonction de hachage. Dans notre exemple, pour les clés "key58" et "key33",
nous avons à chaque fois l’indice 4. Les deux paires clé-valeur sont placées à cet indice.
Une solution possible consiste à doubler la taille du tableau au delà d’un certain ”remplissage”. Dans
notre exemple, la taille du tableau est de 6. La fonction de hachage donnera alors des résultats différents

www.upsti.fr 6/8
Informatique commune PSI

Tableau conte-
Ensemble des clés nant les valeurs
associées aux clés

45

954

”key31”
2678

”key20” Indices
croissants
329

”key58” ”key2”

”key17”
4269

Figure 3 – Schéma illustrant le dictionnaire de l’exemple.

Tableau contenant les


Ensemble des clés
valeurs associées aux clés

”key20” :45

”key2” :954

”key31”
”key31” :2678

”key20”

”key58” :329 , ”key33” :97

”key58” ”key2”

”key17”
”key17” :4269

”key33”

Figure 4 – Schéma illustrant une collision.

www.upsti.fr 7/8
Informatique commune PSI

puisque la taille du tableau est un des paramètres. Toutes les données sont relogées dans le nouveau
tableau avec une répartition bien meilleure, ce qui permet de garder des complexités intéressantes
pour les primitives. Seules la création de ce nouveau tableau et la nouvelle répartition des données
”coûtera” du temps, mais ce temps consommé ne sera que ponctuel, le reste du temps les opérations
seront à coût constant.

IV.5 Exercice 4 : Hashage et Collisions


— Testez avec la fonction de hashage proposée que les clés ”key58” et ”key33” renvoient vers le
même indice.
— Résoudre ce problème en doublant la taille du tableau.
— Procéder de même pour les clés ”key2” et ”key873”
Ci-dessous, un code python permettant de voir l’évolution de la taille en octets d’un dictionnaire.
Celle-ci est grosso-modo doublée lorsque c’est nécessaire.

1 #permet de voir l’évolution dynamique d’un dictionnaire


2 d ={}
3 for i in range (1001):
4 d [ i ]= i
5 print ( sys . getsizeof ( d ))

www.upsti.fr 8/8

Vous aimerez peut-être aussi