tome2-INFO

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 130

Les structures de base en Python

Filières MPSI, PCSI et TSI

Pr. Mohamed ADOCH


Copyright © 2024 M. ADOCH

P UBLISHED BY ATLAS L IBRARY

WWW. ADOCH . COM

Licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License


(the “License”). You may not use this file except in compliance with the License. You may
obtain a copy of the License at http://creativecommons.org/licenses/by-nc/3.0.
Unless required by applicable law or agreed to in writing, software distributed under the
License is distributed on an “AS IS ” BASIS , WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specific language governing
permissions and limitations under the License.

First printing, January 2024


Table des matières

I Les structures de données linéaires


1 List, tuple et str . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.1 Les listes : List 10
1.1.1 Définition et syntaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.1.2 Sous-liste ou slicing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.1.3 Opérations et méthodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.1.4 Liste de listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.1.5 Comment faire une copie d’une liste ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.2 Les n-uplets : tuple 19
1.2.1 Définition et syntaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.2.2 L’avantage d’emploi des tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.3 Les chaînes de caractères : str 22
1.3.1 Définition et exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.3.2 Caractères d’échappement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.3.3 Quelques méthodes utiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.4 Exercices[10] 25

2 Algorithmes de tri et de recherche . . . . . . . . . . . . . . . . . . . . . . 35


2.1 Présentation 35
2.2 Algorithmes de recherche 35
2.2.1 Recherche séquentielle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.2.2 Recherche dichotomique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.3 Algorithmes de tri 37
2.3.1 Tri à bulle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.3.2 Tri par sélection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.3.3 Tri par insertion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.4 Exercices 42
2.4.1 Exercice 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.4.2 Exercice 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.4.3 Exercice 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

3 La démarche d’analyse descendante . . . . . . . . . . . . . . . . . . 45


3.1 Présentation 45
3.2 La démarche d’analyse descendante 45
3.2.1 La démarche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.2.2 Une étude de cas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.2.3 Implémentation en Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.2.4 L’intérêt d’une fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.3 Les fonctions en Python (Approfondissement) 53
3.3.1 Rappel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.3.2 Porté d’une variable et mode de passage . . . . . . . . . . . . . . . . . . . . . . . . 53
3.3.3 Imbrication de fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.3.4 Fonction récursive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.3.5 Quelques fonctions utiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.4 Exercices 59

4 Pile et File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.1 Pile 65
4.1.1 Opérations de base caractérisant une Pile . . . . . . . . . . . . . . . . . . . . . . . . 66
4.1.2 Piles à capacité finie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4.1.3 Piles non bornées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
4.1.4 Exercice d’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
4.2 Files 71
4.2.1 Notion de File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.2.2 Opérations de base caractérisant une File . . . . . . . . . . . . . . . . . . . . . . . . 71
4.2.3 Réalisation d’une structure File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.3 Exercices 72

II Les structures de données non linéaires


5 Dict et Set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
5.1 Présentation 77
5.2 Fonction de hachage 77
5.2.1 Le hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
5.2.2 Table de hachage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
5.3 Les tableaux associatifs : dict 79
5.3.1 Définition et Création . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
5.3.2 Accès aux données et opérations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
5.3.3 Un mini-projet : gestion de contacts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
5.4 Les ensembles : set 92
5.4.1 Définition et création . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
5.4.2 Accès aux données et méthodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
5.5 Pile implémenté par un dictionnaire 94
5.6 Conclusion 95
5.7 Exercices 96

III Les structures de données arborescentes


6 Les Fichiers de textes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
6.1 Présentation 103
6.2 Définitions et vocabulaire 103
6.2.1 Notion de fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
6.2.2 Notion de bloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
6.2.3 Notion de tampon mémoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
6.3 Manipulation de Fichiers textes 104
6.3.1 L’ouverture d’un fichier texte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
6.3.2 La lecture dans un fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
6.3.3 L’écriture dans un fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
6.4 Exercices 108

7 calcul scientifique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111


7.1 Numpy, matplotlib et scipy 111
7.1.1 calcul vectoriel et matriciel avec numpy . . . . . . . . . . . . . . . . . . . . . . . . . 111
7.1.2 Visualisation avec Matplotlib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
7.1.3 Scipy :librairie d’algorithmes scientifiques . . . . . . . . . . . . . . . . . . . . . . . . 123

Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Articles 127
Books 127
Misc 128

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
I
Les structures de données
linéaires

1 List, tuple et str . . . . . . . . . . . . . . . . . . . . . 9


1.1 Les listes : List
1.2 Les n-uplets : tuple
1.3 Les chaînes de caractères : str
1.4 Exercices[10]

2 Algorithmes de tri et de recherche


35
2.1 Présentation
2.2 Algorithmes de recherche
2.3 Algorithmes de tri
2.4 Exercices

3 La démarche d’analyse descen-


dante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
3.1 Présentation
3.2 La démarche d’analyse descendante
3.3 Les fonctions en Python (Approfondissement)
3.4 Exercices

4 Pile et File . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.1 Pile
4.2 Files
4.3 Exercices
1. List, tuple et str

Une structure de données est une manière de représenter les données en mémoire. Avant
de manipuler une structure, il est judicieux de préciser la manière d’attribuer une certaine
quantité de mémoire à cette structure et comment accéder à ses différentes éléments.
Pour chaque structure, il faut définir l’ensemble de ses primitives. Une primitive n’est
qu’une méthode ou une fonction qui permet de rendre un service : par exemple, on définit
une méthode qui permet d’ajouter 1 une donnée à la structure, une autre qui supprime et
ainsi de suite.
L’allocation de mémoire, c’est à dire la quantité de mémoire attribuée à la structure
de données peut être fixé au moment de sa création et ne peut pas être modifiée ; on parle
alors d’une structure de données statique. Dans d’autres cas, l’attribution est déterminée
d’une manière dynamique pendant le déroulement de l’algorithme ; on parle alors d’une
structure de données mutable.
En informatique fondamentale, il existe plusieurs structures de données, à savoir :
— Les structures de données linéaires dont l’accès à ces élément se fait via un indice.
La taille de la structure peut être dynamique(le cas des liste chaînées) comme peut
être statique(le cas de tableaux linéaire)
— Les structures de données associatives dont l’accès se fait via des clés où chaque clé
est associée à une valeur.
— Les structures de données arborescente (Les fichiers,...)
— Les structures de données relationnelles(bases des données relationnelles et les
graphes)
— Les structures de données qui suivent le paradigme Objet.
En python, la principale structure est la classe list. Il s’agit d’une structure hybride, qui
cherche à tirer d’avantage de deux structures de données classique les listes chaînées et les
tableaux.
1. et là encore, il faut spécifier la manière d’ajout : est-ce au début, au milieu ou à la fin de la structure.
10 Chapitre 1. List, tuple et str

Dans ce chapitre, nous allons étudier les structures de données linéaires (list,str, tuple)
et les différentes primitives qui permettent de rendre simple sa gestion en mémoire.

1.1 Les listes : List


1.1.1 Définition et syntaxe
Definition 1.1.1 Une liste[15] (list en python) est une structure de données linéaire
(éventuellement hétérogène). Les données sont séparées par une virgule et délimitées
par deux crochets : une crochet ouvrante "[" et une autre fermante "]".

>>> a = [ ] # c e c i p e r m e t de c r é e r une l i s t e v i d e
# l i s t e d e s j o u r s de l a s e m a i n e
>>> j o u r = [ ’ Lun ’ , ’ Mar ’ , ’ Mer ’ , ’ J e u ’ , ’ Ven ’ , ’Sam ’ , ’Dim ’ ]
# l i s t e c o n t e n a n t d e s donn é e s h é t é r o g è ne
>>> E l e v e = [ ’ A l i ’ , 1 4 , ’ Imane ’ , 1 7 , ’ R a c h i d ’ , 8 ]

Création d’une liste

Comme on peut le constater, une liste peut contenir une collection hétérogène d’objets
(entiers, flottants, chaînes de caractères,autre objets). La fonction built-in len permet
renvoyer le nombre d’éléments d’une liste card(liste) = len(liste)
L’aspect linéaire de la liste se traduit par un indice (index ou offset en anglais), c’est
à dire que l’accès aux données de la structure se fait linéairement via son indice. Deux
notations existent pour l’offset en python :
1. L’offset positif : commence de 0 à n-1 où n = len(liste).
2. L’offset négatif : commence de -n à -1.
Ainsi, pour accéder à l’élément d’indice i, il suffit d’utiliser la syntaxe suivante :
nom_liste [ i ]

Listing 1.1 – syntaxe d’accès aux données

>>> j o u r [ 2 ]
’ Mer ’
>>> E l e v e [ − 3 ]
14

Listing 1.2 – exemple des accès aux données

Une liste en python est mutable c’est à dire, il est possible de modifier sa structure par :
— l’ajout d’un élément :
>>> E l e v e = E l e v e + [ 9 , ’ I b t i s s a m ’ , 1 1 ] # A j o u t à l a f i n
>>> E l e v e
[ ’ A l i ’ , 1 4 , ’ Imane ’ , 1 7 , ’ R a c h i d ’ , 8 , 9 , ’ I b t i s s a m ’ , 1 1 ]

Listing 1.3 – l’ajout par concaténation

— la suppression d’un élément :


1.1 Les listes : List 11

>>> d e l ( E l e v e [ 6 ] )
>>> E l e v e
[ ’ A l i ’ , 1 4 , ’ Imane ’ , 1 7 , ’ R a c h i d ’ , 8 , ’ I b t i s s a m ’ , 1 1 ]

Listing 1.4 – suppression via del


— la mise à jour d’une donnée :
>>> E l e v e [ 4 ] = 1 2 . 5 0
>>> E l e v e
[ ’ A l i ’ , 1 4 , ’ Imane ’ , 1 7 , ’ R a c h i d ’ , 1 2 . 5 0 , ’ I b t i s s a m ’ , 1 1 ]

Listing 1.5 – modification d’une liste


La définition d’une liste se fait d’une manière exhaustive par énumération de ses éléments.
Autrement, pour définir une liste, il suffit d’ouvrir les crochets et d’écrire ses éléments en
les séparant par une virgule.
Cependant, cette manière est fastidieux si on cherche de définir une liste comportant
une grande quantité de données. Une solution à ce problème consiste à définir une liste
par compréhension. Ainsi, supposons qu’on veuille générer, dans l’intervalle [0, 5π] des
impulsions d’un signal défini par la fréquence : f (t) = 3 cos(2t + 0.05) :
from math i m p o r t cos , p i
s i g n a l = [3* cos (2*5* p i / ( n +1) + 0 . 0 5 ) f o r n i n range ( 1 0 0 ) ]

Listing 1.6 – création de liste par compréhension


Le paramètre t est discrétisé dans l’intervalle [0, 5π] et prend comme valeur les points 5∗pin+1
∀n ∈ {0, 1, ..., 99}. la distance entre ses points est appelé le pas : h = b−a
n+1 où a et b sont les
bornes de notre intervalle.

1.1.2 Sous-liste ou slicing


Python permet d’effectuer des coupes (slicing) c-à-d, on peut manipuler des "tranches"
ou sous-liste d’une liste. La syntaxe est identique à celle employée dans la fonction
range(a,b,pas) :
liste[a : b : pas]
La sortie de cette opération est une liste (type list) avec a inclus et b exclu. Les valeurs par
défaut de a, b et pas sont respectivement 0, len(liste), 1. Par exemple :
>>> j o u r = [ ’ Lun ’ , ’ Mar ’ , ’ Mer ’ , ’ J e u ’ , ’ Ven ’ , ’Sam ’ , ’Dim ’ ]
>>> j o u r [ 2 : 4 ]
[ ’ Mer ’ , ’ J e u ’ ]
>>> t r a v a i l = j o u r [ : 5 ]
>>> t r a v a i l
[ ’ Lun ’ , ’ Mar ’ , ’ Mer ’ , ’ J e u ’ , ’ Ven ’ ]
>>>weekend = j o u r [ 5 : ]
>>>weekend
[ ’Sam ’ , ’Dim ’ ]
12 Chapitre 1. List, tuple et str

Listing 1.7 – coupe d’une liste


Pour résumer, la syntaxe maListe[i : j] permet de créer une nouvelle liste contenant les
éléments d’indices entre i et j-1. Lorsque l’indice i est absent, il est prit par défaut à 0. De
même, lorsque j est absent, il est prit par défaut à len(maListe). Ainsi, pour obtenir les m
premiers éléments d’une liste maListe, on fait appel à l’instruction maListe[ :m] et on fait
maListe[(n-m) :] pour obtenir les m derniers éléments où n=len(maListe).
Il existe un troisième paramètre de slicing maListe[début :fin :pas] est le pas par lequel
on avance dans la coupe. Il est prit par défaut à 1 s’il est absent. Ainsi, l’instruction
maListe[ : :-1] permet de créer une nouvelle liste dont l’ordre des éléments est à l’inverse.

1.1.3 Opérations et méthodes


Opérations sur les liste
Il est possible d’effectuer quelques opérations de base sur les listes telles que :
— La concaténation L’opérateur + permet de concaténer deux listes et crée une nouvelle
liste composées de tous les éléments des deux listes :
> > >[1 ,2 ,3]+[4 ,5 ,6 ,7]
[1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9]

— La duplication L’opérateur *n permet de concaténer une liste n fois et crée une


nouvelle liste dont les éléments sont une duplication de la liste courante :
> > >[1 ,2 ,3]*3
[1 ,2 ,3 ,1 ,2 ,3 ,1 ,2 ,3]

— Suppression : la fonction del permet de supprimer un élément ou une coupe d’une


liste :
>>>a = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 ]
>>> d e l ( a [ : 3 ] )
>>>a
[4 ,5 ,6 ,7]

— Les fonctions max, min, sum renvoient respectivement le maximum, le minimum et


la somme des éléments d’une liste :
>>>a = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 ]
>>>max ( a )
7
>>>min ( a )
1
>>>sum ( a )
28

— La modification d’une liste se fait via l’opérateur d’affectation = :


>>>a [ 2 ] = ’ a b c ’
>>> a$ \ \
[ 1 , 2 , " abc " , 4 , 5 , 6 , 7 ]
1.1 Les listes : List 13

>>>a [ 5 : ] = ’ S i n g e s ’
>>>a
[ 1 , 2 , ’ abc ’ , ’ S ing es ’ ]

Généralement, ses opérateurs sont définies dans la classe list à l’aide d’un mécanisme
appelé : surcharge ou polymorphisme 2 et sont accessible via les méthodes déclarées avec la
syntaxe suivante : __methode__ . Par exemple, le comportement de l’opérateur d’addition
+ qui est utilisé comme un opérateur de concaténation pour les listes est défini grâce à la
méthode surchargée __add__.
Le tableau qui suit donne une liste non exhaustive des opérateurs définis dans la classe
list :

2. On traitera ces concepts dans un chapitre consacré à la programmation orientée objet POO
14 Chapitre 1. List, tuple et str

Opérateur Sa méthode Signification Exemple


>>>’Mar’ in jour
True
in __contains__ retourne True si un élément
est dans la liste et False si- Cette expression est identique
non à
jour.__contain__(′ Mar′ )
>>> jour == []
False
== __eq__ retourne True si deux listes
sont égales et False sinon Cette expression est identique
à
jour.__eq__([])
>>> jour > [′ Mon′ ]
False
> __gt__ retourne True si une liste
est supérieur à une autre et ou encore
False sinon. La comparai- jour.__gt__([′ Mon′ ])
son se fait élément par élé-
ment Tant que les deux élé-
ments comparés ont même
type
>>> [2, 3 >= [0]
True
>= __ge__ supérieur ou égale

>>> [2, 3] < [0]


False
< __lt__ strictement inférieur

>>> [2, 3] < [0]


False
< __lt__ strictement inférieur

>>> [2, 3]! = [2]


True
!= __ne__ différent

TABLE 1.1 – Opérateurs de base pour manipuler des objets de type list
1.1 Les listes : List 15

Primitive de base : méthodes


La classe list en python est fournie avec un ensemble de primitives. Comme indiqué
dans la section de présentation, une primitive est une fonction qui permet de rendre un
service. Elle peut modifier la structure ou tout simplement renvoyer une information sur
celle-ci. Par exemple, la méthode clear permet de vider une liste et autrement dit, il permet
de supprimer tous ses éléments mais sa référence mémoire reste non modifié. La syntaxe
générale employée pour appeler une méthode est la suivante :

maListe.maMthode(paramtres)

Dans le tableaux qui suit, on donne un ensemble de méthodes qui sont propres à la classe
list :

Méthode Description
append(e) ajoute de e à la fin d’une liste
insert(i,e) Elle insère e à la position(index) i dans une liste et
renvoie None en cas de succès et erreur en cas d’un
index hors sa plage des indices
extend(iterable) étendre une liste par l’ajout à la fin des éléments
d’un objet itérable
remove(e) supprime la première occurrence de e dans la liste.
Elle retourne None en cas de succès et erreur si e
n’existe pas dans la liste
pop() retourne le dernier élément d’une liste et supprime
celui-ci
pop(i) retourne l’élément d’indice i d’une liste et supprime
celui-ci. Elle renvoie une erreur en cas de i est "in-
dex out of range"
sort() trie la liste par ordre croissant. Elle possède un pa-
ramètre nommé reverse de valeur par défaut false.
sort(reverse=True) donne un tri par ordre décrois-
sant
reverse() inverse l’ordre d’une liste
count(valeur) renvoie le nombre d’occurrence d’une valeur dans
la liste
TABLE 1.2 – Quelques méthodes utiles pour manipuler une liste

>>>a = [ 1 , 2 , 3 ]
>>>a . a p p e n d ( 5 ) # [1 ,2 ,3 ,5]
>>>a . a p p e n d ( [ 7 , 8 ] ) # [1 ,2 ,3 ,5 ,[7 ,8]]
>>>a . i n s e r t ( 1 , ’ ok ’ ) # [ 1 , ’ ok ’ , 2 , 3 , 5 , [ 7 , 8 ] ]
>>>a . e x t e n d ( [ ’ a ’ , ’ b ’ , ’ c ’ ] ) # [ 1 , ’ ok ’ , 2 , 3 , 5 , [ 7 , 8 ] , ’ a ’ , ’ b ’ , ’ c ’ ]
>>>a . remove ( [ 7 , 8 ] ) # [ 1 , ’ ok ’ , 2 , 3 , 5 , ’ a ’ , ’ b ’ , ’ c ’ ]
>>>a . pop ( ) # [ 1 , ’ ok ’ , 2 , 3 , 5 , ’ a ’ , ’ b ’ ]
>>>a . pop ( 1 ) # [1 ,2 ,3 ,5 , ’ a ’ , ’ b ’]
>>>a . s o r t ( ) # r e n v o i e None e t t r i l a l i s t e : [ 1 , 2 , 3 , 5 , ’ a
’ , ’ b ’]
16 Chapitre 1. List, tuple et str

>>>a . r e v e r s e ( ) # r e n v o i e None e t i n v e r s e s e s é l é m e n t s
>>>a . i n s e r t ( 4 , ’ a ’ ) # renvoie :[ ’ b ’ , ’ a ’ ,1 ,2 , ’ a ’ ,3 ,5]
>>>a . c o u n t ( ’ a ’ ) # renvoie l ’ entier 2

Listing 1.8 – quelques méthodes de la classe list

1.1.4 Liste de listes


Comme list est un objet python contenant une collection d’objets, on peut créer une
liste dont les éléments sont aussi des listes. Ceci est utile dans le cas où vous travaillez sur
des matrices.
La matrice suivante  
1 2 3 4
M =  0 −1 2 5.2
−2 3 2.5 0

peut être représentée de la façon suivante :


M= [ [ 1 , 2 , 3 , 4 ] , [ 0 , − 1 , 2 , 5 . 2 ] , [ − 2 , 3 , 2 . 5 , 0 ] ]
M[ 2 ] # renvoie la l i s t e [ −2 ,3 ,2.5 ,0]
M[ 1 ] [ 3 ] # renvoie la valeur 5.2

Listing 1.9 – list qui représente une matrice

Un des avantages des structures de données linéaire est qu’on peut parcourir ses éléments
à l’aide d’un indice. On peut parcourir les éléments d’une liste élément par élément via la
boucle for :
— parcours par l’indice :
for x in range ( len ( l i s t e ) ) :
p r i n t ( " é l é ment d ’ i n d i c e {} e s t {} " . $ f o r m a t ( x , l i s t e [ x ] ) )

Listing 1.10 – itération par indice

— parcours par élément :


for x in l i s t e :
print (x)

Listing 1.11 – itération par élément

1.1.5 Comment faire une copie d’une liste ?


Definition 1.1.2 — Mutabilité. Un objet python est dit mutable lorsqu’on peut le
modifier sans changer son adresse en mémoire.

Pour l’instant, les seules structures mutables que l’on connaisse sont les listes

R Les types int, long, float, bool, complex et str ne sont pas des objets mutables
1.1 Les listes : List 17

Les pièges de mutabilité :

Une méconnaissance du mécanisme de la mutabilité peut avoir une conséquence


fâcheuse lorsqu’on cherche à créer une copie d’un objet mutable. En effet, lorsque var1 est
une variable, l’instruction var2 = var1 se contente de créer un nouveau référencement en
mémoire. Par exemple, les instructions b = a et b.append(5) créent la situation suivante :

>>>a = [ 7 , 2 , 9 ]
>>>b=a
>>> i d ( a ) == i d ( b ) # r e n v o i e True
>>>b . a p p e n d ( 5 )
>>>a
[7 ,2 ,9 ,5]
>>>b
[7 ,2 ,9 ,5]

Listing 1.12 – notion de référence

Comme vous pouvez le constater, l’instruction b = a permet de créer un référencement sur


le même objet en mémoire et toute modification de a va affecter b aussi. Pour copier un
objet mutable dans un autre mutable, il suffit d’utiliser le slicing qui permet de créer une
nouvelle liste d’adresse différente :

>>>c=a [ : ]
>>>c . a p p e n d ( ’ a b c ’ )

Listing 1.13 – copie superficielle par slicing


18 Chapitre 1. List, tuple et str

Considérons maintenant le cas d’une liste de liste :

>>>a = [ [ 1 , 2 , 3 ] , [ 4 , 5 , 6 ] , [ 7 , 8 , 9 ] ]
>>>b=a [ : ]
>>> i d ( a ) == i d ( b ) # Renvoie F a l s e
>>> i d ( a [ 1 ] ) == i d ( b [ 1 ] ) # R e n v o i e T r u e

Listing 1.14 – mutabilité sur un exemple

Nous constatons sur cet exemple que nous n’avons pas réalisé une copie de première ni-
veau : a et b référencent effectivement deux emplacement de mémoire tandis que a[i] et b[i]
référencent le même objet mutable et toute modification de l’un entraîne une modification
identique de l’autre :
1.2 Les n-uplets : tuple 19

Il est possible de s’en sortir avec une définition par compréhension :


>>>b = [ x [ : ] f o r x i n a ]

Listing 1.15 – une copie superficielle


Cependant, cette technique ne résout pas le problème s’il y un troisième niveau d’objets
mutable, voire plus. C’est pourquoi que la méthode de slicing crée une copie superficielle.
Pour faire une copie profonde d’un objet mutable, on utilise la méthode copy.
>>> from copy i m p o r t d e e p c o p y
>>>a = [ [ 1 , 2 , 3 ] , [ 4 , 5 , 6 ] , [ 7 , 8 , 9 ] ]
>>>b= d e e p c o p y ( a )
>>> i d ( a ) == i d ( b ) # Renvoie F a l s e
>>> i d ( a [ 1 ] ) == i d ( b [ 1 ] ) # Renvoie F a l s e

Listing 1.16 – une copie profonde

1.2 Les n-uplets : tuple


1.2.1 Définition et syntaxe
Definition 1.2.1 — tuple. Un tuple[15] est une structure de données linéaire dont les
éléments sont séparés par virgules "," et délimités par une parenthèse ouvrante "(" et
une parenthèse fermante ")". L’accès à une donnée se fait à l’aide de mécanisme d’index
comme pour les listes. Cependant, un tuple est immuable. Autrement dit, il est fermé à
la modification.

>>> e1 = ( 1 , 0 , 0 )
>>> e1
(1 ,0 ,0)
>>> e1 [ 0 ]
1
>>> e [ 1 ] = 3 # r e n v o i e une e r r e u r
20 Chapitre 1. List, tuple et str

Listing 1.17 – exemple de tuple

Une conséquence immédiate de l’aspect immuable est qu’on ne peut pas appliquer les
méthodes append, insert, pop, remove, sort, extend et clear car elles modifient la structures.
Les seules méthodes qu’on peut appliquer sont, donc, count et index qui renvoient respecti-
vement le nombre d’occurrences d’un élément et l’indice d’un élément dans la structure
s’il existe :
>>> e2 = ( 0 , 1 , 0 )
>>> e1 . c o u n t ( 2 )
2
>>> e2 . i n d e x ( 1 )
1

Listing 1.18 – quelques méthodes de la classe tuple

Cependant, si un élément est mutable alors on peut modifier sa structure. Cela affecte
seulement l’élément en question et non plus la structure dans laquelle est inclue :
>>> n o t e s = ( ’ A l i ’ , [ 1 2 , 1 5 ] , ’ Imane ’ , [ 8 . 5 0 , 1 6 ] )
>>> n o t e s
( ’ A l i ’ , [ 1 2 , 1 5 ] , ’ Imane ’ , [ 8 . 5 , 1 6 ] )
>>> n o t e s [ 1 ] . a p p e n d ( 1 3 )
>>> n o t e s
( ’ A l i ’ , [ 1 2 , 1 5 , 1 3 ] , ’ Imane ’ , [ 8 . 5 , 1 6 ] )
>>>

Listing 1.19 – modification d’un objet mutable dans uns structure non mutable

Les opérateurs définis dans le tableau table1 de la deuxième section de ce chapitre pour les
listes sont aussi valide pour les tuples :
>>> ’ A l i ’ i n n o t e s
True
>>> e1 > e2
True
>>> n o t e s [ 2 : ]
( ’ Imane ’ , [ 8 . 5 0 , 1 6 ] )
>>>

Listing 1.20 – slicing pour les tuples

1.2.2 L’avantage d’emploi des tuples


L’avantage d’utilisation de tuple est le verrouillage de l’accès aux données en mode
d’écriture. Pour modifier un tuple, il suffit de le convertir en une liste : l = list(mon_tuple).
Une fois les modifications sont effectuées, on fait la conversion réciproque : mon_tuple =
list(l). La seule mise en garde qu’on doit prendre en compte est qu’il y a un changement
de référence au niveau de l’objet mon_tuple car il est immuable.
Les tuples permettent de faire des échanges d’objets au niveaux de mémoire. Pour
échanger les valeurs de deux objets, il suffit d’utiliser la notion de tuple.
1.2 Les n-uplets : tuple 21

>>> a = 2
>>> b = 7
>>> a , b = b , a
>>>a
7
>>> b
2
>>>

Listing 1.21 – échange des valeurs via tuple

Si on ne spécifie pas les délimiteurs lors d’affectation d’un ensemble de valeurs à une
variable, python le prend par défaut comme un tuple :

>>> x = 1 , 2
>>> x
(1 , 2)

Listing 1.22 – remarque sur les parenthèses d’un tuple

Cependant, si on veut définir un tuple contenant un seul élément, il faut ajouter une virgule
à la fin :

>>> y = ( 3 , )
>>> y
(3 ,)
>>> t y p e ( y )
< ’ class ’ , tuple >
>>> z = ( 3 )
>>> z
3
>>> t y p e ( z )
<’ class ’ , int >

Listing 1.23 – remarque sur les parenthèses d’un tuple

Si l’échange fonctionne bien pour les objets de type int, il fonctionne aussi parfaitement
bien pour les autres objets immuable : bool, float, str, tuple :

>>> e2 = 1 , 0 , 0
>>> e1 = 0 , 1 , 0
>>> e1 , e2 = e2 , e1
>>> e1
(1 , 0 , 0)
>>> e2
$ (0 , 1 , 0)
$>>>

Listing 1.24 – l’échange entre deux variables


22 Chapitre 1. List, tuple et str

1.3 Les chaînes de caractères : str


1.3.1 Définition et exemple
Une chaîne de caractères[15] est une suite de caractères délimités par simple quote,
double guillemets ou triple guillemets :

>>> s = ’ He i s a man ’
>>>c= " He ’ s \ a \ man "
>>> l = " " " I l a d i t : " b o n j o u r " " " "
>>> t y p e ( s )
< ’ c l a s s ’ , ’ s t r ’>

Listing 1.25 – différentes délimiteurs d’une chaîne de caractères


Si l’apostrophe (’) est parmi les caractères d’une variable de type str alors les délimiteurs
sont les guillemets et inversement, si guillemets sont parmi les caractères d’une chaîne
alors on utilise le simple quote comme délimiteur. Dans le cas où les deux sont inclus dans
une valeur, on préféra d’utiliser le triple guillemets.
L’usage de triple guillemets est un peut particulier car il permet de définir une chaîne
de caractères dont on veut garder sa mise en forme sur plusieurs lignes. Si il est utiliser au
début d’une structure (fonction, classe, module) il est considéré comme un docString. Les
docString sont affichées grace à la fonction built-in help
Une chaîne de caractères est une structure de données linéaire non modifiable. On peut,
donc, parcourir ses caractères à l’aide de mécanisme indexe :
>>> s = ’ He i s a man ’
>>> s [ 1 ] renvoie le caract è re ’e ’

Listing 1.26 – l’accès aux caractères d’une chaîne


Extraction de tranches ou des sous chaînes est possible (Slicing) :
>>> s = ’ He i s a man ’
>>> s [ 2 : 5 ] # r e n v o i e l a s o u s c h a î ne ’ i s ’

Listing 1.27 – sous chaîne d’une chaîne de cractères


Tous les opérateurs de base définis dans le tableaux table1 de première section sont définis
également définis pour manipuler les chaînes de caractères (teste d’appartenance, les
opérateurs de comparaison, concaténation, duplication, ...).
Cependant, la comparaison entre deux chaînes se fait grâce à l’ordre défini dans le
code ASCII pour Windows et le code unicode pour Linux.
Les mêmes opérations définies pour les objets de type list sont définie également pour
les objets de type str et tuple et c’est pourquoi nous nous parlons, dans ce chapitre, des
structures linéaires. La seule différence est que str et tuple sont immuable par rapport à
l’aspect mutable de list.

1.3.2 Caractères d’échappement


Le symbole \ (antislash) est spécial : il permet d’interpréter quelque caractères non
imprimable du code ASCII. Ainsi, il transforme le caractère :
1.3 Les chaînes de caractères : str 23

— \n : en un saut de ligne
— \t : en une tabulation
— \b : en un backspace
— \a : en un bip
— \’ : en un ’ (apostrophe), mais il ne ferme pas la chaîne de caractères
— \" : en un "(guillemet), mais il ne ferme pas la chaîne de caractères
— \\ : en un \ (Antislash)
>>> s = ’ He \ ’ s \ t a man ’
" He ’ a man "

1.3.3 Quelques méthodes utiles


Nous avons déjà employé la méthode format pour substituer les accolades {} avec les
valeurs de ses arguments. Cependant, cette méthode ne modifie pas la valeur de la chaîne 3
mais elle crée une autre chaîne dont les accolades sont remplacés par les valeurs de ses
arguments :
>>> p r i x =12.14
>>> s = " Le p r i x de l ’ a r t i c l e e s t {} "
>>> p r i n t ( s . format ( prix ) )
" Le p r i x de l ’ a r t i c l e e s t 1 2 . 1 4 "
>>> print (s)
" Le p r i x de l ’ a r t i c l e e s t {} "

Listing 1.28 – formatage de variables dans une chaîne


La méthode format permet également de formater 4 des valeurs des objets tels que :
binaire,octale, hexadécimale , int, str et float. Pour cela, il suffit d’utiliser le symbole % de
la façon suivante :
>>> p r i x =12.1498624
>>> s = " Le p r i x de l ’ a r t i c l e e s t %.2 f "
>>> p r i n t ( s %( p r i x ) )
" Le p r i x de l ’ a r t i c l e e s t 1 2 . 1 4 "
>>> print (s)
" Le p r i x de l ’ a r t i c l e e s t {} "

Listing 1.29 – formatage des variables dans une chaîne


Le caractère f signifie que la valeur formatée est de type float et qu’on veut afficher
cette valeur avec seulement de chiffre après la virgule : %.2f. Les autres formats sont
données dans le tableau table 3
Le tableau qui suit vous donne quelques méthodes utiles pour la gestion de chaînes de
caractère :

3. Une valeur de type str est immuable


4. Voir la documentation officielle de python qui traite les entées-sortie : https ://-
docs.python.org/fr/3/tutorial/inputoutput.html
24 Chapitre 1. List, tuple et str

Symbole Signification
%d Formater une valeur entière
%f Formater une valeur réelle
%s Formater une valeur textuelle
%o Formater une valeur octale
%x Formater une valeur hexadécimale

TABLE 1.3 – Formats d’affichage

méthode syntaxe Signification


join() chaine.join(ListChaines) Renvoie une nouvelle chaîne contenant
tous les éléments de la liste ListChaines,
concaténés en utilisant chaine comme sé-
parateur
find() chaine.find(sousChaine) Renvoie la position de la première occur-
rence de sousChaine dans chaine. Renvoie
-1 si sousChaine n’ést pas trouvée.
split() chaine.split([sep]) Renvoie une liste contenant la chaîne dé-
coupée en plusieurs sous-chaînes. Par dé-
faut la séparation se fait sur les blancs (es-
paces, tabulations, retours à la ligne), sauf
si un autre séparateur est spécifié.
replace() chaine.replace(avant,apres) Renvoie une nouvelle chaîne dans laquelle
chaque occurrence dans chaine de la sous-
chaîne avant est remplacée par apres
strip() chaine.strip([caractères]) Renvoie une nouvelle chaîne dans laquelle
tous les blancs (ou tout caractère présent
dans caractères s’il est donné en para-
mètre) sont ôtés au début et à la fin de
chaine.
lower() chaine.lower() Renvoie une nouvelle chaîne où toutes les
lettres de chaine ont été converties en mi-
nuscules.
upper () chaine.upper() Renvoie une nouvelle chaîne où toutes les
lettres de chaine ont été converties en ma-
juscules.
capitalize chaine.capitalize() Renvoie une nouvelle chaîne dans laquelle
le premier caractère de chaine est trans-
formé en majuscule et les suivants en mi-
nuscules.
TABLE 1.4 – Quelques méthodes utiles pour manipuler de texte
1.4 Exercices[10] 25

1.4 Exercices[10]

Les structures de données linéaires permettent de stocker un ensemble de valeurs dans


l’ordre de leurs insertions. Chaque valeur possède un indice qui détermine sa position dans
la structure et grâce à cet indice, on peut parcourir (boucle while ou for) l’ensemble de
valeurs.
La structure de données list est mutable : on peut modifier ses éléments sans modifier
sa référence en mémoire. Cependant, les autres structures telles que tuple et str sont
immuables : toute modification entraînera un changement au niveau de sa référence
mémoire. Je vous conseille, donc, de consacrer du temps pour étudier ce chapitre et de
maîtriser parfaitement ses détails techniques relatifs au langage Python.
Exercise 1.1 Soit liste une séquence des nombres réels.
1. Écrire une fonction somme_moyenne_variance(liste) qui prend en argument une
liste de nombres réels et qui renvoie un tuple composé de la somme, la moyenne
et la variance de ces nombres.
2. Écrire une fonction min_max(liste) qui prend en argument une liste de nombres
réels et qui renvoie un tuple composé de la valeur minimale et maximale de ces
nombres
3. Écrire un algorithme, puis un programme python qui fait appel aux fonctions
som_moy_var et min_max

Exercise 1.2 Dans cet exercice,


 on représente
une matrice M comme une liste de listes.
0 1 2 3
Par exemple la matrice A = 4 5 6 7 

8 9 10 11
est représentée par M=[[0,1,2,3], [4,5,6,7],[8,9,10,11]]
1. Écrire un programme qui réalise l’addition de deux matrices A et B de mêmes
dimensions N et M.
2. En multipliant une matrice A de dimensions n et m avec une matrice B de
dimensions m et p on obtient une matrice C de dimensions n et p :
A(n,m) * B(m,p) = C(n,p).
Écrire un programme qui réalise le produit de deux matrices A et B



Exercise 1.3 On représente un vecteur par un tuple. Par exemple, le vecteur U (x1 , x2 , x3 , x4 , x5 )
est représenté par un tuple U = (x1 , x2 , x3 , x4 , x5 )
1. Écrire un programme qui réalise l’addition de deux vecteurs U et V de même
dimension n
2. Écrire un programme qui réalise le produit scalaire de deux vecteurs U et V de
même dimension n
3. Écrire un programme qui réalise le produit vectoriel de deux vecteurs U et V de
même dimension n

26 Chapitre 1. List, tuple et str

Exercise 1.4 On vous propose dans cet exercice de programmer les fonctions suivantes :
1. est_lettre(e) qui prend en paramètre une lettre et qui renvoie True si e est une
lettre. Par exemple, est_lettre(’r’) rendra True alors que est_lettre(’ !’) rendra
False.
2. nbrMot qui prend en entrée une chaîne de caractères, et rend le nombre de mots
de cette chaîne. Par exemple, nbrMot(’Cette chaîne est longue, elle contient huit
mots’) rendra 8.
3. est_phrase qui détecte si une chaîne de caractères est une phrase ou non. On
considère que les chaînes de caractères analysés sont constituées au plus d’une
phrase.

Exercise 1.5 Un palindrome est une entité qui se lit de la même façon de gauche à
droite et de droite à gauche. Par exemple, ’laval’ est un mot palindrome. De même, ’la
mariée ira mal’ est une phrase palindrome. Concernant les nombres, ’12321’ est aussi
un palindrome.
Écrire une fonction python qui renvoi True si le mot passé en argument est palin-
drome et False sinon. ■

Exercise 1.6 — Fonctions utilitaires. L’objectif de cet exercice est la programmation


d’un ensemble de fonctions intermédiaires que vous pouvez utiliser dans les problèmes
proposés ci-dessous..
1. Écrivez un code qui définit une fonction apparait(lt,e) qui effectue la même
action que e in lt.
2. Écrivez un code qui saisit un mot, transforme ce mot en liste de caractères, puis
transforme cette liste en chaîne en insérant un espace entre chaque caractère et
affiche la chaîne. Jeux de tests :

altitude ==> a l t i t u d e
et123 ==> e t 1 2 3

3. Écrivez un code qui définit une fonction indiceMaximum(lt) qui renvoie l’indice
du maximum d’une liste numérique lt (non vide), c-à-d. qu’elle effectue la même
action que : lt.index(max(lt)). Jeux de tests :

[1, 1.5, 2, -2, 10, 5.5] ==> 4


[9] ==> 0
[1, -1, 12] ==>1 2

4. Écrivez un code qui définit une fonction nbrOccurs(lt,e) qui calcule et renvoie le
nombre de fois qu’un élément e apparaît dans une liste lt, et -1 si lt n’a pas le bon
type. Jeux de tests :

nbroccurs(["a",1,2,3,2,2,5,2],2) ==> 4
nbrOccurs(2,2) ==> -1
nbroccurs(["a",1,2,3,2,2,5,2],9) ==> 0
1.4 Exercices[10] 27

5. Écrivez un code qui définit une fonction unique(lt) qui calcule et renvoie la liste
sans recopie des doublons d’une list lt. Jeux de tests :

1 2 9 7 3 4 2 3 5 6 7 3 4 1 8 9 ==> [1, 2, 9, 7, 3, 4, 5, 6, 8]
"a" 1 2 3 2 2 5 2.0 ==> [’a’, 1, 2, 3, 5]
"ab" "bb" "c" "C" "ab" ==> [’ab’, ’bb’, ’c’, ’C’]

6. Écrivez un code qui définit une fonction lchiffres(n) qui renvoie la liste des
chiffres (du poids faible au poids fort) d’un entier positif n. Jeux de tests :

lchiffres(205468) ==> [8, 6, 4, 5, 0, 2]


lchiffres(2) ==> [2]

7. Écrivez un code qui définit une fonction lfibonacci(n) qui, pour un entier positif
n, calcule et renvoie la liste des n premiers termes de la suite de Fibonacci :

u0 = 0, u1 = 1

et
∀n ∈ N, un+2 = un+1 + un .
Jeux de tests :

16 ==> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
0 ==> []
1 ==> [0]
2 ==> [0, 1]
3 ==> [0, 1, 1]

8. Soit t un tableau bidimensionnel de 10x15 entiers. Écrivez un code qui définit :


(a) Une procédure afficherT2d(t,nligs,ncols) qui affiche un tableau t de nligs
lignes et ncols colonnes.
(b) Une procédure remplirT1(t,nligs,ncols) qui remplit le tableau selon (T1)
(c) Une procédure remplirT2(t,nligs,ncols) qui remplit le tableau selon (T2).
(d) Que faut-il modifier dans remplirT2 pour remplir selon les colonnes ?
a)

Problem 1.1 Un polynôme P à coefficients dans R s’écrit sous la forme :

k=n k
x
P(x) = ∑ k! = a0 + a1x + a2x2 + ... + anxn
k=0

où les coefficients ak ∈ R.
Le type Polynôme n’existe pas en python et pour travailler avec les polynômes, on
utilisera un astuce simple : on pourrait stocker les coefficients ak dans une liste LP tels que
pour chaque indice k de la liste LP, ak est stocké à l’indice k : LP = [a0 , a1 , a2 , ..., an ].
Par exemple, si P(x) = −4x7 + 3.5x5 − x2 + 1 alors la liste associée à P serait :

LP = [1, 0, −1, 0, 0, 3.5, 0, −4]


28 Chapitre 1. List, tuple et str

indice 0 1 2 3 4 5 6 7
Monôme a0 x 0 a1 x 1 a2 x2 a3 x 3 a4 x 4 a5 x5 a6 x 6 a7 x 7
coefficient 1 0 -1 0 0 3.5 0 -4
Dans la suite de ce problème, on adoptera cette forme de représentation afin d’écrire un
ensemble de fonctions nécessaires pour gérer les polynômes à coefficients dans R.
k=n
xk
1. Construire, à la main, la liste associée au polynôme P(x) = ∑ k! Pour n = 5.
k=0
Réciproquement, donner le polynôme associée à la liste [−2, 3, 0, 0, 1, −1, −1, 2].
2. Écrire une fonction generate(n : int)-> list , d’argument un entier n et qui renvoie
k=n
xk
la liste associée au polynôme P(x) = ∑ k! .
k=0
3. Écrire une fonction toString(LP : list)-> str , d’argument une liste associée au
polynôme P et qui renvoie une représentation textuelle sous forme d’une chaîne de
caractères S=’an Xˆ n + an−1 Xˆ n-1...+a1 X + a0 ’.
Par exemple :

>>> toString([-2, 0, 3, 0, 0, 1])


"-2Xˆ 5 + 3X ˆ 2 - 2"

4. Écrire une fonction value(LP : list, a : float)-> float , d’argument une liste LP asso-
ciée au polynôme P, un nombre réel a et qui renvoie la valeur P(a) qui évaluer P en a
Par exemple :

>>> value([-2, 0, 3, 0, 0, 1], -1)


2.5

5. L’algorithme de Horner est un algorithme qui permet de diminuer le coût d’évaluation


de P en x en minimisant le nombre d’opérations nécessaires pour calculer P(x). Par
exemple, si P(x) = ax4 +bx3 +cx2 +dx+e, alors on aura 14 opérations pour calculer
P(x) :
— 4 multiplications pour ax4 = a × x × x × x × x
— 3 multiplications pour bx3 = b × x × x × x
— 2 multiplications pour cx2 = c × x × x
— 1 multiplication pour dx = d × x
— 4 additions ax4 + bx3 + cx2 + dx + e
L’algorithme de Horner permet de réduire le nombre d’opérations selon le schéma
suivant : P(x) = a0 + x(a1 + x(a2 + x(... + x(an−1 + an x)...)). Avec l’exemple précé-
dent, on aura 8 opérations P(x) = e + x × (d + x × (c + x × (b + a × x))) au lieu 14
opérations.
Écrire une fonction horner(LP : list, a :float)-> float , d’argument une liste LP as-
sociée au polynôme P, un nombre réel a et qui renvoie la valeur P(a) qui évaluer P
en a selon l’algorithme de Horner
Par exemple :

>>> horner([-2, 0, 3, 0, 0, 1], -1)


2.5
1.4 Exercices[10] 29

6. Écrire une fonction scale(LP : list, k : float)-> list , d’argument une liste LP asso-
ciée au polynôme P, un nombre réel k et qui renvoie une list associée au polynôme
(kP)(x) = kP(x) Par exemple :

>>> scale([-2, 0, 3, 0, 0, 1], 3)


[−6, 0, 9, 0, 0, 3]

7. Écrire une fonction add(LP : list, LQ : list)-> list , d’argument une liste LP asso-
ciée au polynôme P, une liste LQ associée au polynôme Q et qui renvoie une list
associée au polynôme (P + Q)(x) = P(x) + Q(x) Par exemple :

>>> add([-2, 0, 3, 0, 0, 1], [ 0, 3, 2] )


[−2, 3, 5, 0, 0, 1]

8. Écrire une fonction sub(LP : list, LQ : list)-> list , d’argument une liste LP associée
au polynôme P, une liste LQ associée au polynôme Q et qui renvoie une list associée
au polynôme (P − Q)(x) = P(x) − Q(x) Par exemple :

>>> sub([-2, 0, 3, 0, 0, 1], [ 0, 3, 2] )


[−2, −3, 1, 0, 0, 1]

9. Écrire une fonction mult(LP : list, LQ : list)-> list , d’argument une liste LP asso-
ciée au polynôme P, une liste LQ associée au polynôme Q et qui renvoie une list
associée au polynôme (P × Q)(x) = P(x) × Q(x) Par exemple :

>>> mult([−2, 0, 3, 0, 0, 1], [0, 3, 2])


[0, −6, 5, 0, 6, 0, 3, 2]

10. Écrire une fonction derived(LP : list)-> list , d’argument une liste LP associée au
polynôme P et qui renvoie une list associée au dérivée de la fonction polynôme
(P)(x) Par exemple :

>>> derived([−2, 0, 3, 0, 0, 1])


[0, 6, 0, 0, 5]

Problem 1.2 — Calculs dans un tableau de dimension 2. Le but de ce problème est


d’écrire un programme qui remplit de valeurs aléatoires un tableau d’entiers de dimension
2, et qui fait quelques calculs dans ce tableau. Un tableau est une liste de dimension
fixe : On ne peut pas, donc, modifier sa structure par ajout (append, insert, extend) ou par
suppression (pop, remove, del).

L’exécution de votre programme devra donner à l’écran un affichage semblable


à l’exemple donné ci-dessous à la fin de ce problème.

Le tableau est de format (taille, dimension) N × P, où N et P sont des constants du


programme de type int.
30 Chapitre 1. List, tuple et str

Question 1 :
Écrivez les instructions permettant de fixer le format 3 × 12. Une fonction en python,
est-elle autorisée d’accéder aux valeurs N et P ?

Question 2 :
Écrivez la fonction générer_tab ( ) sans paramètres qui génère un tableau tab de taille
P(tab est donc de dimension 1) avec les entiers aléatoires dans [1, 20] et qui renvoie tab

Question 3 :
Écrivez la fonction remplir_tab ( ) sans paramètres qui remplit le tableau tab de format
N × P avec les entiers aléatoires dans [1, 20] et affiche son contenu à l’écran, sous forme
d’un rectangle de nombres de N lignes et de P colonnes. La fonction renvoie le tableau tab
(on pourra utiliser la fonction générer_tab () )

Question 4 :
Écrivez la fonction somme_ligne(lig, t) qui calcule , affiche et renvoie la somme des
éléments de la ligne lig du tableau t de taille N × P

Question 5 :
Écrivez la fonction somme_ligne_max(t) qui :
1. affiche la somme des éléments de chaque ligne du tableau t de taille N × P (en
appelant la fonction précédentes) ;
2. calcule et renvoie la somme maximale obtenu sur une ligne du tableau t.

Question 6 :
On désire chercher sur chaque ligne de la liste, les séquences (slices) de deux éléments
supérieurs à une valeur donnée (c’est-à-dire deux éléments consécutifs supérieur à cette
valeur).
Écrivez la fonction sequence_deux_elements_sup (t, val) qui, pour chaque ligne, affiche
les indices j de t où se trouvent deux éléments consécutifs dont la valeur est supérieur à val.
L’affichage se fera sous forme intervalle [j, j+1] ; comme dans l’exemple ci-dessous.

Question 7 :
Écrivez la fonction teste qui, en appelant les fonctions précédentes :
1. remplit la liste d’entiers aléatoires de [1, 20] et en affiche le contenu à l’écran ;
2. calcule et affiche la somme des éléments de chaque ligne, puis la somme maximale ;
3. pour chaque ligne, affiche les séquences de deux éléments supérieurs à 12
Exemple d’affichage obtenu à l’écran par l’exécution du programme :
1.4 Exercices[10] 31

Question 8
Généralisez la fonction de la question 6, pour afficher les séquences d’éléments de
valeurs supérieure à val, quelle que soit leur longueur (un élément, ou deux, ou trois, etc.)
Par exemple, si l’on prend l’exemple ci-dessus, on obtiendra :
sequence d’éléments supérieurs à 8 :
ligne 0 : intervalle[0,0] ; intervalle[2,2] ; intervalle[4, 7] ; intervalle[9,9] ;
ligne 1 : intervalle[0, 2] ; intervalle[4, 6] ; intervalle[10,10] ;
ligne 2 : intervalle[2,6] ; intervalle[8,8] ; intervalle[10,10] ;

Problem 1.3 — Carrée Magique


. Définition :
On appelle carré d’ordre n un tableau bi-dimensionnel n × n. Un carré sera représenté
sous la forme d’une liste unidimensionnelle d’entiers.

Définissez la constante TMAX= 100 (nombre maximal de cases d’une liste). Dans la
suite de problème, le type ENTList définit une liste de TMAX entiers et le type LCarre est
équivalent au type ENTList.

Stockage linéaire d’un tableau bidimensionnel :

Il permet d’optimiser son espace mémoire et correspond à effectuer la transformation


suivante :

Par exemple la liste suivante [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]] sera
32 Chapitre 1. List, tuple et str

optimisée par la liste [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

1. Écrivez une fonction indexTab2d(j,k,n) qui renvoie l’index linéaire de la case en


(j,k) d’une liste bidimensionnelle à n colonnes.
2. Écrivez une fonction evalCase(t,j,k,n) qui renvoie la valeur de l’élément en (j,k)
d’une ENTList t de n colonnes.
3. Écrivez une procédure fixerCase(t,j,k,n,valeur) qui fixe l’élément en (j,k) d’une
ENTList t de n colonnes à la valeur valeur.
4. Écrivez une fonction saisirOrdreCarre(nmax) qui renvoie un entier, saisi par
l’utilisateur, entier qui doit être impair, supérieur à 1 et tel que n2 soit inférieur ou
égal à nmax (entier).
5. Écrivez une procédure initialiserCarre(t,n) qui initialise à zéro chacun des éléments
d’une ENTList t d’ordre n.

Algorithme
L’algorithme ci-après ne fonctionne que si n est impair.
Il place les nombres dans l’ordre 1, 2, ..., n2 .
— Placez le 1 dans la case située une ligne en dessous de la case centrale.
— Après avoir placé k dans une case de coordonnées (i, j), placez k + 1 dans la case (l,
c) = (i + 1, j + 1), en défilant au-delà des bordures, c.-à-d. que si la case dépasse la
dernière ligne (resp. la dernière colonne), la case sélectionnée est celle en première
ligne (resp. en première colonne). En cas d’occupation d’une case, la case suivante
est (l, c) = (i + 2, j). Par construction, on démontre que cette case n’est pas occupée.
— Exemple : Voici le carré d’ordre 3 obtenu à l’aide de cette méthode.
816
357
492
6. Déroulez l’algorithme sur le carré d’ordre 3 et vérifiez que vous obtenez celui de
l’exemple.
7. Écrivez une fonction suivant(k,n) qui renvoie le suivant de l’entier k dans l’ensemble
circulaire [1..n] .
8. De même, écrivez une fonction precedent(k,n) qui renvoie le précédent de l’entier k
dans l’ensemble circulaire [1..n] .
9. Écrivez alors une procédure creerCMagique1(c,n) qui crée le carré magique d’ordre
n dans un LCarre c selon l’algorithme ci-dessus.
10. Écrivez un script de sorte qu’il :
— Saisit l’ordre du carré dans un entier (par exemple n ).
— Déclare un TCarre (par exemple c ).
— Construit le TCarre magique d’ordre n dans c .
— Enfin affiche c .
11. Testez. (Pour n = 3 et n = 5)

8 1 6 17 24 1 8 15
3 5 7 23 5 7 14 16
4 9 2 4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
1.4 Exercices[10] 33
2. Algorithmes de tri et de recherche

2.1 Présentation

Dans ce chapitre, nous allons présenter quelques algorithmes de tris et de recherche.


Nous présenterons trois algorithmes classiques de tri tels que : tri par propagation, tri par
sélection et tri par insertion.

2.2 Algorithmes de recherche

2.2.1 Recherche séquentielle

Principe

Le principe de l’algorithme de recherche séquentielle[13] consiste à parcourir une liste


d’éléments dans l’ordre de ses indices jusqu’à ce qu’un élément recherché soit trouvé ou
bien que la fin de la liste soit atteinte et le rang (indice) de l’élément est alors retourné.

Algorithme

Parcourir une liste à l’aide d’une boucle while ou for et à chaque itération i (une tour
de la boucle) on vérifie si l’élément d’indice i coïncide avec l’élément recherché ; si c’est
le cas alors on retourne cet indice i. Si on a pas sorti avec cet indice alors on retourne None
ou un message d’erreur.
36 Chapitre 2. Algorithmes de tri et de recherche

Data: Liste l, donnée x, Compteur i, Taille_Liste N


Result: index ou None
while i < N do
if l[i] = x then
return i;
end
i ← i+1
end
return None
Algorithm 1: pseudo code de la recherche séquentielle

Programme
L’implémentation python de cet algorithme est immédiate :

def recherche ( l i s t e , data ) :


n = len ( l i s t e )
k = 0
while k < n :
i f l i s t e [ i ] == d a t a :
return i

Notons qu’une fonction en python renvoie par défaut la valeur None si aucun renvoi
n’est pas défini. Une fois la fonction recherche(liste, data) n’a pas renvoyé l’index k alors
après while, elle retourne la valeur None.

2.2.2 Recherche dichotomique


Principe
L’algorithme de recherche dichotomique est un algorithme efficace et rapide pour la
recherche d’un élément dans une liste triée.
Le principe de cet algorithme consiste à diviser la liste en deux parties et à comparer
la valeur recherchée avec l’élément situé au milieu du tableau (l’élément de centre). Si la
valeur recherchée correspond à l’élément du centre, alors l’algorithme s’arrête et renvoie
l’indice de cet élément. Sinon l’algorithme va répéter la recherche uniquement dans la
partie qui peut contenir la valeur recherchée (puisque la liste est triée).

Algorithme
Étant donné une liste L de taille n et une donnée data qu’on veut rechercher son indice
dans L. On suppose que les éléments de la liste sont triés en ordre croissant.
L’intervalle initial de recherche est [a, b] avec a=0 et b=len(liste) -1. Tant que [a, b] est
un intervalle c’est à dire a ≤ b alors on calcule c l’indice du centre et on compare l’élément
d’indice c avec data. Trois cas, donc, sont envisageables :
— Si L[c]= data alors on retourne l’indice i
— Si L[c] < data alors on lance la recherche dans l’intervalle [c+1, b] (remarquons ici
que la seule valeur modifiée est celle de la variable a)
— Si L[c] > data alors on lance la recherche dans l’intervalle [a, c-1] (b = c-1)
2.3 Algorithmes de tri 37

d’où l’algorithme qui suit :

Data: Liste triée L, Taille_Liste n, Donnée data


Result: boolean
a ← 0;
b ← n − 1;
while a <= b do
c ← (a + b)//2;
if L[c] = data then
return c;
else
if L[c] < data then
a ← c + 1;
else
b ← c − 1;
end
end
end
return None;
Algorithm 2: pseudo code de la recherche dichotomique

Programme
Voici une implémentation python de l’algorithme précédente :

def recherche_dichomique (L, data ) :


a =0
b= l e n ( L ) −1
w h i l e a <=b :
c = ( a+b ) / / 2
i f L [ c ]== d a t a :
return c
e l i f L[ c ] < data :
a=c +1
else :
b=c −1

2.3 Algorithmes de tri


Un algorithme de tri[6] est, en informatique ou en mathématiques, est un algorithme
qui permet d’organiser une collection d’objets selon un ordre déterminé. Les objets à trier
font donc partie d’un ensemble muni d’une relation d’ordre. Les ordres les plus utilisés
sont l’ordre numérique et l’ordre lexicographique. Un tri est dit en place s’il n’utilise qu’un
nombre très limité de variables et qu’il modifie directement la structure qu’il est en train
de trier
38 Chapitre 2. Algorithmes de tri et de recherche

2.3.1 Tri à bulle

Principe

Le principe de tri à bulle (ou encore par propagation) consiste à parcourir plusieurs
fois une liste, comparer deux à deux des éléments adjacents et échange s’ils ne sont pas
ordonnés. Le processus de parcours s’arrête lorsqu’on parcours la liste sans faire d’échange.
Par exemple, considérons la liste l = [5, 3, 7, 2, 8, 4] de taille n = 6 :
3 5 7 2 8 4
3 5 7 2 8 4
— Itération 1 : 5 3 7 2 8 4 3 5 2 7 8 4
3 5 2 7 8 4
3 5 2 7 4 8
3 5 2 7 4 8
3 2 5 7 4 8
— Itération 2 : 3 5 2 7 4 8 3 2 5 7 4 8
3 2 5 4 7 8
3 2 5 4 7 8
2 3 5 4 7 8
2 3 5 4 7 8
— Itération 3 : 3 2 5 4 7 8 2 3 4 5 7 8
2 3 4 5 7 8
2 3 4 5 7 8

Algorithme

Data: Liste L, Taille_Liste n


Result: liste triée en place
n ← len(L);
echange ← V rai;
while echange do
echange ← Faux;
k ← 0;
while k < n − 1 do
if L[k] > L[k + 1] then
c = L[k];
L[k] = L[k+1];
L[k+1]=c;
echange ← V rai;
end
k ← k + 1;
end
end
Algorithm 3: pseudo code de tri à bulle
2.3 Algorithmes de tri 39

Programme
On donne ici deux implémentations possible de cet algorithme : La première variante
est une traduction directe de l’algorithme précédente :

def t r i _ b u l l e ( l i s t e ) :
n = len ( l i s t e )
echange = True
while echange :
echange = False
k = 0
while k < n −1:
i f l i s t e [k] > l i s t e [k +1]:
l i s t e [ k ] , l i s t e [ k +1] = l i s t e [ k +1] , l i s t e [ k ]
echange = True
k = k + 1

Notons que la fonction ne renvoie aucune valeur car la liste passée en argument est
modifié par un algorithme de tri en place et notre liste se trouve triée par ordre croissant à
la fin de l’algorithme.
La deuxième variante est une conséquence immédiate de tri à bulle : à chaque itération,
les plus grandes valeurs sont placées à la fin et les petites valeurs se "remontent" au début
de la liste comme les bulles d’un liquide les plus "légers" remontent le plus rapidement à
sa surface :

def t r i _ b u l l e ( l i s t e ) :
n = len ( l i s t e )
f o r i i n range ( n −1) :
f o r k i n r a n g e ( n− i − 1 ) :
i f l i s t e [k] > l i s t e [k +1]:
l i s t e [ k ] , l i s t e [ k +1] = l i s t e [ k +1] , l i s t e [ k ]

2.3.2 Tri par sélection


Principe
Le tri par sélection consiste à :
— Sélectionner (Rechercher l’index) du plus petit élément de la liste et l’échanger avec
le premier élément
— Sélectionner du plus petit élément de la liste entre les positions 2 et n−1 et l’échanger
avec le second élément
— ...
— Sélectionner (Rechercher l’index) de la liste entre les positions i et n −1 et l’échanger
avec le i-ème élément
— ...
— Sélectionner du plus petit élément entre les positions n − 2 et n − 1 et l’échanger
avec l’élément en position n − 2
Par exemple, considérons la liste : l=[5, 3, 7, 2, 8, 4] de taille n = 6
40 Chapitre 2. Algorithmes de tri et de recherche

— liste initiale : 5 3 7 2 8 4
— Itération 1 : 5 3 7 2 8 4 =⇒ 2 3 7 5 8 4
— Itération 2 : 2 3 7 5 8 4 =⇒ 2 3 7 5 8 4
— Itération 3 : 2 3 7 5 8 4 =⇒ 2 3 4 5 8 7
— Itération 4 : 2 3 4 5 8 7 =⇒ 2 3 4 5 8 7
— Itération 5 : 2 3 4 5 8 7 =⇒ 2 3 4 5 7 8
— liste finale : 2 3 4 5 7 8

Algorithme

Nous donnons tout d’abord l’algorithme qui permet de sélectionner l’indice de plus
petit élément d’une liste entre l’indice i et la fin de la liste. On applique, donc, le principe
mathématique de Min(E) :


m∈E
m = Min(E) ⇔
∀x ∈ E, m ≤ x

Data: Liste L, Taille_Liste n, Index de départ i


Result: l’indice du min m
n ← len(L) ;
m ← i # m ∈ E;
k ← i + 1;
while k < n do
# ∀x ∈ E l[m] < x;
if L[m] > L[k] then
m = k;
end
k ← k + 1;
end
return m;
Algorithm 4: pseudo code de minimum

L’algorithme de tri par sélection est le suivant :


2.3 Algorithmes de tri 41

Data: Liste L, Taille_Liste n


Result: l’indice m du min
n ← len(L) ;
i ← 0;
while i < n do
m ← minimum(L, i);
if m! = i then
c ← L[m];
L[m] ← L[i];
L[i] ← c;
end
i ← i + 1;
end
Algorithm 5: pseudo code de tri par sélection

Programme
Voici une implémentation python des algorithmes de recherche du minimum (getIndex-
Min) et de tri par sélection (selection_sort) :

def getIndexMin (L , i ) :
n = len (L)
m = i
f o r k i n r a n g e ( i +1 , n ) :
i f L [m] > L [ k ] :
m = k
return m

def s e l e c t i o n _ s o r t (L) :
n = len (L)
for i in range ( n ) :
m = getIndexMin (L , i )
i f m != i :
L [ i ] , L [m] = L [m] , L [ i ]

2.3.3 Tri par insertion


Principe
Étant donnée T[x0 , x1 , ..., sn−1 ] une liste de données à trier. Le principe de tri par
insertion consiste à parcourir la liste T à partir de i où i ∈ 1, 2, ..., n et considérer que La
liste T soit triée jusqu’à l’élément i − 1. On prend, à chaque itération l’élément d’indice i
et on cherche à l’insérer à sa place parmi les i premiers éléments.

Algorithme
[6] Pour insérer un élément d’indice i dans sa place parmi les i premiers éléments
on procède par un décalage à droite de ses éléments jusqu’à l’élément qu’on a pris soit
supérieur à T[j-1] ou j ≤ 0 sachant que l’élément retiré est T[i] qu’on nomme par carte :
42 Chapitre 2. Algorithmes de tri et de recherche

Data: Liste T , Taille_Liste n


Result: liste triée
n ← len(T ) ;
i ← 1;
while i < n do
carte ← T [i];
j ← i;
while j > 0 and carte < T [ j − 1] do
T [ j] ← T [ j − 1];
j ← j − 1;
end
T [ j] ← carte;
i ← i + 1;
end
Algorithm 6: pseudo code de tri par insertion

Programme
On traduit instruction par instruction l’algorithme précédente et on obtient en python
le code qui suit :

def i n s e r t i o n _ s o r t (T) :
n = len (T)
for i in range (1 , n ) :
c a r t e = T[ i ]
j = i
w h i l e j >0 and c a r t e < T [ j − 1 ] :
T[ j ] = T[ j −1]
j = j −1
T[ j ] = c a r t e

2.4 Exercices
2.4.1 Exercice 1
1. Concevez un algorithme de recherche du maximum dans un ensemble à n éléments.
2. Nous supposerons ici que l’ensemble considéré ne contient pas deux fois la même
valeur. Proposez un algorithme simple de recherche du deuxième plus grand élément

2.4.2 Exercice 2
1. Construire trois listes de 10000 entiers : liste1 contient les entiers de 1 à 10000
rangés dans l’ordre croissant ; liste2 contient les entiers de 10000 à 1 rangés dans
l’ordre décroissant ; liste3 contient 10000 entiers choisis de manière aléatoire avec la
fonction randint parmi les entiers de 1 à 10000 bornes comprises.
2.4 Exercices 43

2. Mesurer le temps d’exécution des trois algorithmes de tri (tri par insertion, tri à
bulle, tri par sélection) pour trier chacune des trois listes précédentes. On utilisera la
fonction time du module time. Par exemple :
from time import time
debut=time ( )
tri_insertion ( liste1 )
fin = time ( )
print ( debut - fin )

3. Mesurer sur les mêmes listes le temps d’exécution des algorithmes de tris utilisés
par la fonction sorted et par la méthode sort(). La syntaxe est "sorted(iste)" et
"liste.sort()".
4. Mesurer maintenant le temps d’exécution de la fonction sorted et de la méthode
sort()sur une liste de 100000 entiers choisis de manière aléatoire avec la fonction
randint parmi les entiers de 1 à 10000 bornes comprises.

2.4.3 Exercice 3
L’objectif est d’écrire un programme qui trie une liste de mots et les range dans l’ordre
lexicographique (ordre des dictionnaires).
1. Écrire la définition de la variable "alphabet" : alphabet = "AaàBbCcDdEeéèFfGgH-
hIiJjKkLlMmNnOoPpQqRrSsTtUuùVvWwXxYyZz"
2. Écrire une fonction ordre_alphabetique(c1,c2) qui prend en argument deux carac-
tères alphabétiques et renvoie -1 si c1 est avant c2, 1 si c2 est avant c1 et 0 si c1 =
c2. On pourra utiliser la méthode index qui renvoie l’indice d’un élément dans une
chaîne de caractères.
3. Écrire une fonction ordre_lexicographique(m1,m2) qui prend en argument deux
mots et renvoie -1 si ”m1 < m2” pour l’ordre lexicographique, 0 si ”m1 = m2” et 1
si ”m1 > m2”. On utilisera la fonction ordre_alphabetique.
4. Écrire une fonction tri_lexicographique(liste) qui prend an argument une liste de
mots et renvoie la liste triée. On utilisera la fonction ordre_alphabetique etl’algo-
rithme du tri par insertion.
3. La démarche d’analyse descendante

3.1 Présentation
Dans ce chapitre, nous allons présenter la démarche d’analyse descendante. L’accent
est mis ici sur la démarche permettant de décomposer un problème qualifié difficile en
problèmes simples et élémentaires.
Découper un problème en sous problèmes nous impose de concevoir pour chaque
sous-problème un sous programme et de rassembler l’ensemble de sous-programmes
pour construire la solution finale. La notion de sous-programme ou de fonction est une
conséquence immédiate de la démarche d’analyse descendante.
Nous présenterons également la notion de fonction et quelques aspects techniques qui
lui sont associées et nous finirons, ce chapitre, par l’introduction de quelques fonctions
prédéfinies en python.

3.2 La démarche d’analyse descendante


3.2.1 La démarche
La démarche d’analyse descendante consiste à décomposer un problème complexe et
difficile en sous-problèmes et les sous-problèmes en petits sous-problèmes et ainsi de suite
jusqu’au raffinement simples ou élémentaires.
L’opération principale de cette démarche descendante est la décomposition du problème
initial en sous-problèmes ; voici la représentation arborescente associée :

Voici un exemple de la vie quotidienne : faire des courses dans une grande surface
— Problème initial : faire des courses
— Sous-Problème 1 : "faire des courses" se décompose en :
1. Se préparer : écrire la liste des achats
46 Chapitre 3. La démarche d’analyse descendante

F IGURE 3.1 – Arborescence de décomposition

2. Sortir de la maison
3. Allez chez la boutique
4. faire effectivement des courses
5. revenir à la maison
6. ranger les achats dans leurs emplacement (La cuisine)
7. se laver les mains.
— Sous-problème 1.4 : faire effectivement des courses se décompose en :
1. rentrer dans la boutique
2. prendre un chariot
3. Parcourir la grande surface :Pour chaque article de votre liste d’achats, allez à
sa place et le poser dans le chariot
4. Passer à la caisse
5. Payer la somme
6. Sortir de la boutique.
— Sous problème 2.3 : se décompose en ...
Si l’on doit concevoir un logiciel qui permettrait à un robot d’assurer ces différentes tâches,
il y aurait sans doute des millions de lignes de code. Il serait donc judicieux de décomposer
le problème initial en sous problèmes simples bien raffinés afin de mener à bien ce projet.

3.2.2 Une étude de cas


Problème à résoudre :
écrire un programme réalisant la saisie d’une suite de valeurs (des entiers) rentrée au
clavier, puis afficher dans l’ordre croissant, à raison de 10 valeurs par ligne. On considérera
une suite de 1000 valeurs entières au maximum.

Analyse du problème :
L’analyse du problème passe par l’identification des variables (données de programme)
d’entrées et de sorties d’une part et d’autre part par les traitements à effectuer :
3.2 La démarche d’analyse descendante 47

Les variables : Une lecture rapide du problème nous permettra d’identifier les objets
manipulés par le programme : — Une constante entière NB_MAX = 1000 contenant le
nombre maximal à saisir au clavier. — Une suite de valeurs : Pour cela, nous utiliserons
une liste pour y stocker ces valeurs.

Les traitements : Dans cette phase, nous allons décomposer le problème selon la
démarche d’analyse descendante :
1. Sous-problème 1 : saisir la suite de valeurs
2. Sous-problème 2 : mettre en ordre croissant cette suite
3. Sous-problème 3 : afficher la liste triée selon le format imposé.
(1)Saisir la suite de valeurs : On propose la méthode (algorithme) suivante :
1. Initialement, on crée une liste vide. Soit suite cette liste.
2. On répète la lecture au clavier d’un entier puis sa mémorisation dans la liste suite
exactement n fois avec n ≤ NB_MAX.
3. à la fin, on retourne cette liste.

Saisir la suite de valeurs


Entrées :
n: nombre d’élément à lire (< NB_MAX)
l: une liste vide
Sorties: La liste l
Début
vérifier que n < NB_MAX
pour k allant de 0 à n-1 faire
lire une valeur entière x au clavier
ajouter x à la fin de l
FinPour
retourner l
Fin

(2) Tri de la suite 1


On propose la l’algorithme de tri par sélection basé sur le principe qui suit :
étant donné une liste l=[l[0], l[1], ..., l[n-1]].
1. Rechercher l’indice de l’élément minimal dans l=[l[0], l[1], ..., l[n-1]].
2. Une fois trouvé, l’échanger avec l’élément de première position (d’indice 0).
3. répéter récursivement 1 et 2 sur la liste [l[1], ..., l[n-1]], puis [l[2], ..., l[n-1]] et ainsi
de suite.

1. Voir le chapitre 12
48 Chapitre 3. La démarche d’analyse descendante

Tri par sélection


Entrées :
l: une liste de valeurs entières
Sorties: La liste l triée en ordre croissant
Début
n <-- len(l)
Pour i allant de 0 à n-2 faire
indice <--- minimal(l[i:])
Si indice != i alors:
échanger(liste, i, indice)
FinSi
FinPour
retourner l
Fin

Il reste maintenant à préciser comment trouver l’indice de l’élément minimal d’une liste
quelconque l. Le plus simple est de fixer que l’indice de minimum est initialement indice=0
puis parcourir la liste à partir de 1. À l’itération k, Si l[k] < l[0] alors dans ce cas on met à
jour la valeur de variable indice à k puisqu’on a trouvé un autre inférieur au minimum de
départ. d’où l’algorithme qui suit :

recherche de l’indice du minimum


Entrées :
l: une liste de valeurs
Sorties: l’indice de l’élément minimum
Début
n <-- len(l)
indice <--- 0
Pour i allant de 1 à n-1 faire
Si l[indice] < l[i] alors:
indice <--- i
FinSi
FinPour
retourner indice
Fin

(3) Afficher la liste selon le format imposé Pour afficher une liste de n éléments à raison
de grid=10 par ligne (Format imposé 1 )on peut utiliser la méthode suivante :

Parcourir la liste dans l’ordre croissant des indices avec affichage de 10 premiers
éléments, puis afficher les 10 éléments qui suivent et ainsi de suite jusqu’à arriver à la fin
n
de la liste. On remarque que si n=200 et grid=10 alors il y a grid lignes à afficher puisque
n = 10 × 20 Ceci pourrait conduire à l’algorithme suivant :
3.2 La démarche d’analyse descendante 49

Afficher une liste dans une grille de grid colonnes


Entrées :
l: une liste de valeurs
grid: Entier indiquant le nombre d’éléments à afficher par ligne
Sorties: <affichage à l’écran>
Début
n <-- longueur(l)
pour k allant de 0 à n-1 faire
Si (k % grid) = 0 alors
<aller à la ligne>
sinon
<afficher l[k] et rester dans la ligne>
FinSI
FinPour
Fin

3.2.3 Implémentation en Python

F IGURE 3.2 – Arborescence de la décomposition dans l’étude de cas

Après l’analyse, on peut passer directement à la phase de programmation appelée


implémentation en Python. Cela revient à traduire les différents algorithmes en Python :
50 Chapitre 3. La démarche d’analyse descendante

recherche de l’indice du minimum


"""
@Date : 05/03/2019
@Auteur : Pr M.ADOCH
@Spécification : ce programme réalise la saisie,
la mémorisation d’une suite de n entières telle
que(n <= NB_MAX=1000) puis son affichage à raison
de grid=10 par lignes dans l’ordre croissant des
valeurs
"""
NB_MAX = 1000
n = int(input("Entrer le nombre d’élément: "))
assert n <= NB_MAX

#La lecture au clavier d’une suite de valeurs


suite = []
for k in range(n):
x =int(input(f"Entrer la valeur numéro {k}:"))
suite.append(x)

#Le tri par sélection d’une suite


for i in range(n-1):
indice = i
for j in range(i+1,n):
if suite[indice]> suite[j]
indice = j
if indice !=i:
suite[indice], suite[i]= suite[i], Lsuite[indice]

#Affichage de suite
grid=int(input("Entrer le nombre d’élément à afficher par ligne:"))
for k in range(n):
if (k % grid) == 0 and k!=0:
print()
print(f"{L[k]} ",end=’ ’)
print("\n--------------------------------")

print("Fin du problème")

La lecture de ce programme semble un peu illisible et pour améliorer sa lisibilité, on


utilise la notion de fonction ou sous-programme qu’on a vu en trimestre 1. Les impératives
de la démarche d’analyse descendante consiste, donc, à implémenter chaque algorithme
dans une fonction. La figure 3.2 représente la décomposition choisie pour notre problème
initial.
Dans la suite, nous allons traduire chaque algorithme de notre décomposition en 4
3.2 La démarche d’analyse descendante 51

fonctions principales :

La lecture de la suite

def s a i s i r ( n ) :
l = []
for k in range ( n ) :
x = i n t ( i n p u t ( f " E n t r e r l a v a l e u r numero { k } : " ) )
l . append ( x )
return l

Recherche de l’indice du minimum

d e f minimum ( l ) :
n = len ( l )
indice = 0
for i in range (1 , n ) :
if suite [ indice ]> suite [ i ] :
indice = i
return indice

Tri par sélection

def t r i S e l e c t ( l ) :
f o r i i n range ( n −1) :
i n d i c e = minimum ( l [ i : ] )
i f i n d i c e != i :
l [ i n d i c e ] , l [ i ]= l [ i ] , l [ i n d i c e ]

Affichage selon le format imposé

def affchage ( l , grid ) :


n = len ( l )
for k in range ( n ) :
i f ( k % g r i d ) == 0 and k ! = 0 :
print ()
p r i n t ( f " { s u i t e [ k ] } " , end = ’ ’ )
p r i n t ( " \ n−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− " )

Maintenant, on va essayer de résoudre notre problème initial en appelant chaque


fonction dans son endroit approprié :
52 Chapitre 3. La démarche d’analyse descendante

Solution du problème

NB_MAX = 1000
t e x t 1 = " E n t r e r l e nombre d ’ e l e m e n t a a f f i c h e r p a r l i g n e : "
t e x t 2 = " E n t r e r l e nombre t o t a l de v a l e u r s : "
n = int ( input ( text1 ) )
grid = int ( input ( text2 ) )
a s s e r t n <= NB_MAX

suite = saisir (n)


triSelect ( suite )
afficher ( suite , grid )

3.2.4 L’intérêt d’une fonction


Programmer en décomposant en sous-programme, ou du moins en parties indépen-
dantes, recèle quantité de vertus. Nous en présentons ci-dessous l’essentiel. Notons que
l’on parle de programmation structurée mais aussi de programmation modulaire. Il y a
cependant une nuance terminologique entre les deux termes, en ce sens que l’on pourrait
estimer que la programmation modulaire est une exigence de la programmation structurée.
1. simplification - Lisibilité - Indépendance :
Décomposer un programme en sous-programmes permet une simplification de la
programmation et une meilleure lisibilité du programme, ce qui conduit à une
minimisation des risques d’erreurs. A cela s’ajoute la possibilité de travailler indé-
pendamment sur différentes parties d’un programme (travail en équipe)
2. Tests indépendants :
Certains sous-programmes peuvent être testés indépendamment. Si l’on travaille
sur un "gros" programme, qui se décompose en sous-programmes, les différentes
fonctions Python correspondantes peuvent être écrites, testées et validées indépen-
damment les une des autres. On peut ainsi limiter la difficulté d’analyse des erreurs
et le temps de mise au point.
3. Entités de traitement : Certaines tâches constituent un tout : au niveau de l’analyse,
on a identifié certaines tâches bien cernées, comme par exemple le tri de la liste, qui
est, par certains aspects, totalement indépendant, à la fois de la lecture des données,
et de l’affichage des résultats. Cela doit conduire naturellement à la mise en œuvre
d’un sous-programme spécifique. On pourra d’ailleurs constater que le programme
pourrait significativement être amélioré en se limitant à la modification du sous-
programme de tri (il en existe de bien plus efficaces !). Dans ce cas, il suffirait de
remplacer cette procédure par une autre, sans modifier quoi que ce soit au reste du
programme.
4. Plusieurs occurrences d’une même tâche dans un problème ou dans un domaine
d’applications : Certaines tâches se retrouvent à plusieurs
√ reprises pour traiter un
même problème. Prenons l’exemple du calcul de x. En Python, une fonction
appelée sqrt pré-existe dans le module mathématique math. On peut la considérer
comme une primitive du langage. Dans une application, il aurait été souhaitable, si
elle n’existait pas déjà, de développer une telle fonction, notamment pour le cas où
3.3 Les fonctions en Python (Approfondissement) 53

ce calcul se serait répété (plutôt que d’avoir à dupliquer le code).

3.3 Les fonctions en Python (Approfondissement)


3.3.1 Rappel
Une fonction en python est exactement une fonction au sens mathématique. Par défini-
tion, une fonction est la donnée de trois choses :
1. Un ensemble de paramètres d’entrées d’un ensemble appelé : ensemble de départ E
(ou encore ensemble d’arguments),
2. Un ensemble de paramètres de sorties d’un ensemble appelé : ensemble d’arrivé F ,
3. Et une relation fonctionnelle (ou procédé, ou règle) qui décrit comment à partir de
l’entrée x ∈ E, arriver à "calculer" (fournir une réponse) une sortie y ∈ F et en écrit :

f :E →F

x 7−→ y
avec y = f (x) si possible ou une procédure (méthode de calcul)
La définition d’une fonction en python respecte la syntaxe suivante :
syntaxe générale d’une fonction python
def nom_fonction(Arguments):
"""
DocString
"""
global <variables globales>
<Bloc d’instructions>
return <valeur de la sortie>

Le nom de la fonction doit respecter les règles de nommage utilisées pour identifier
des variables :
— Il doit commencer par une lettre (y compris la lettre _ ),
— Il peut contenir des chiffre,
— Il ne doit pas contenir de l’espace ou d’opérateurs -, +, @, ...),
— Il ne doit pas être un mot clé réservé au langage if, for, while, ...
Si le nom est composé de plusieurs mots, utiliser la règle du dos de chameau (--̂-̂) : mot-
MotMot. La liste des arguments entre parenthèse peut avoir zéro ou plusieurs paramètres
séparés par virgule.

3.3.2 Porté d’une variable et mode de passage


variables locales et globales
Cette définition permet juste de déclarer une fonction et ne permet pas de l’exécuter.
L’exécution passe par un processus appelé Appel d’une fonction. Cet appel se fait de la
manière suivante :
nom_fonction(arg1, arg2, ..., argn)
54 Chapitre 3. La démarche d’analyse descendante

Notons ici que les arguments arg1, arg2, ... argn peuvent être des valeurs ou des
variables globales déclarées en dehors de son code. Les variables internes c’est-à-dire
celles déclarées à l’intérieure de la fonction ont une porté locales.
L’exemple qui suit montre que les variables a, b et c sont locales et les variables x, y, s
et d sont globales :

def somme (a, b):


c = a + b
return c
def diff (a, b):
return a-b

x = 3
y = 7

s = somme(x, y)
d = diff (x, y)
print(f"{x} + {y} = {s}"}
print(f"{x} - {y} = {d}"}

Le mot return permet de stocker le résultat du traitement dans la référence d’une


fonction et provoque son arrêt. En absence du mot return, python renvoi par défaut la
valeur None. Cela permet de stocker la valeur d’une variable locale à une variable global
via le mécanisme d’affectation.
Une fonction peut appeler une variable globale en mode lecture seulement. Pour
autoriser une fonction de modifier sa valeur il faut l’introduire par le mot global. L’exemple
qui suit retourne une erreur car la variable global c n’est pas déclarée au moment de son
appel :

def f (a):
global c, d
c = c+1
d += a + c
f(3) # erreur
c = 1 # Ok
d = 0 # Ok
f (3) # c = 2 et d = 5

Mode de passage
Passage par valeur :
Dans un passage par valeur, les variables effectifs (celle passée à la fonction au moment
de son appel) sont copiés dans les paramètres formels. Les valeurs des arguments formels
restent inchangés après l’appel de la fonction. Les types non mutables (int, float, str,
complex, bool, tuple...) sont passés par valeur.
L’exemple qui suit montre que les variables a et b passées à la fonction echange reste
inchangées après son appel :
3.3 Les fonctions en Python (Approfondissement) 55

def echange (a, b):


a, b = b, a

a = 10
b = 20
print (f"Avant echange: a={} et b={}".format(a, b))
echange(a, b)
print (f"Apres echange: a={} et b={}".format(a, b))

Les variables a et b à l’extérieur de la fonction echange sont copiées dans les variables
locales a et b et la fonction echange va permuter ses variables locales et non plus les
variables globales c’est pourquoi les variables a=10 et b= 20 reste inchangé après son
appel.

Passage par référence


Dans un passage par référence, les paramètres effectifs sont remplacés dans les pa-
ramètres formels. Les valeurs des arguments formels sont changés après l’appel de la
fonction. Les types mutables (listes, ensembles, dictionnaires ...) imitent le mode de pas-
sage par variable. L’exemple qui suit montre que la liste a est modifié après l’appel de la
fonction ajouter(a, x) :
passage par variable

def a j o u t e r ( a , x ) :
a . append ( x )

a = [1 , 2 , 3]
p r i n t ( f " Avant l ’ a p p e l : a = { a } " )
a j o u t e r ( a , 5)
p r i n t ( f " Apres l ’ a p p e l : a = { a } " )

Valeurs par défaut


Une fonction peut être déclarée avec des paramètres ayant une valeur de départ. Si
l’utilisateur omet l’un des paramètres au moment de l’appel, la valeur par défaut sera prise
en considération :
def point (x, y=1, z=2):
s = f"M({x}, {y}, {z})"
print(s)

point() # erreur car la variable x n’a pas de valeur.


point(2) # affiche: M(2, 1, 2)

Python autorise d’appeler la fonction sans trop respecter l’ordre des arguments au
moment de la déclaration. Il suffit d’utiliser le nom du paramètre au moment de l’appel et
de préciser la valeur qu’il prend :
56 Chapitre 3. La démarche d’analyse descendante

def point (x=1, y=1, z=2):


s = f"M({x}, {y}, {z})"
print(s)

point() # affiche: M(1, 1, 2).


point(y=3, z=20 x=-2) # affiche: M(-2, 3, 20)

3.3.3 Imbrication de fonctions


On peut définir une fonction (fonction fille ou interne) à l’intérieur d’une autre (fonction
mère). La fonction fille n’est pas visible en dehors de sa fonction mère et Les paramètres
formels de la fonction fille restent locales et ne sont pas visible dans la fonction mère. Les
variables globales restent visible de partout :

def f1( ):
x=1
def f2( ) :
x=2
print("Au niveau de fonction f2, x=", x)
f2 ()
print( ”Au niveau de fonction f1, x=", x)
f1 ()

Ceci permet d’afficher le résultat suivant :


Au niveau de fonction f2, x = 2
Au niveau de fonction f1, x = 1

Si on introduit le mot global dans la fonction fille alors les variables locales concernées
de la fonction mère seront modifiées :
def f1( ):
x=1
def f2( ) :
global x
x=2
print("Au niveau de fonction f2, x=", x)
f2 ()
print( ”Au niveau de fonction f1, x=", x)
f1 ()

Ceci permet d’afficher le résultat suivant :


Au niveau de fonction f2, x = 2
Au niveau de fonction f1, x = 2

On peut passer le nom d’une fonction (sa référence) comme argument d’une autre
fonction. L’exemple qui suit montre l’usage d’un tel passage de fonction :
3.3 Les fonctions en Python (Approfondissement) 57

passage d’une fonction comme argument

def f ( x ) :
r e t u r n x*x

d e f d f ( f , x0 ) :
h = 0.000000000001
r e t u r n ( f ( x0+h ) − f ( x0 ) ) / h

On peut assigner une fonction à une variable comme tout autre objet python
— X=f
— X(5)
On peut également placer les fonctions dans des listes, tuples ou dictionnaires :
— d={’a’ : f, ‘b’ : g}
— d[’a’](5)

3.3.4 Fonction récursive


Une fonction est dite récursive si elle s’appelle elle-même au cours de son exécution.
La récursivité est très utile pour une structure de données récursive. Elle permet d’exprimer
d’une manière transparente la solution de plusieurs problèmes :
— Récurrences mathématiques classiques,
— Certains algorithmes de Tri,
— Recherche dichotomique,
— ...
Par exemple, la factorielle d’un entier positif peut se définir d’une manière itérative :


0! = 1 , si n = 0
n! = 1 × 2 × ... × n , si n > 0

version itérative

def f a c t o r i e l l e ( n ) :
a s s e r t n >= 0
f = 1
f o r k i n range ( 2 , n +1) :
f *= k
return f

On peut aussi définir la factorielle d’une manière récursive :


0! = 1 , si n = 0
n! = (n − 1)! × n , si n > 0
58 Chapitre 3. La démarche d’analyse descendante

version récursive

def f a c t o r i e l l e ( n ) :
a s s e r t n >= 0
i f n == 0 : r e t u r n 1
r e t u r n n * f a c t o r i e l l e ( n −1)

3.3.5 Quelques fonctions utiles


L’expression lambda
On peut définir rapidement une fonction à l’aide de l’expression lambda selon la
syntaxe suivante
Syntaxe
lambda arg1, arg2, ..., argn : f(arg1, arg2, ..., argn)

Cela définit une fonction anonyme qui contient un simple renvoi. Par exemple, la
fonction f : x 7−→ f (x) = x(x − 1) peut être déclarer comme suit :
Exemple
lambda x : x*(x-1)

fonction map()
Pour mapper une fonction avec un itérateur, on utilise la fonction prédéfinie map().
C’est une fonction à deux paramètres ; Le premier sert à définir une expression et le
deuxième est un itérateur. Par exemple map(f, liste) permet de retourner un itérateur de
type map qu’on peut le convertir à une liste (via list) :

[ f (liste[0]), f (liste[1]), ..., f (liste[len(liste) − 1])]

On peut passer plusieurs objets itérables à la fonction map :


syntaxe de map()
map(f, objIt1, objIt2, ...)

fonction filter()
syntaxe de filter()
filter(fonction, sequence)

La fonction filtrer permet de filtrer tous les éléments d’une séquence pour lequel la
fonction retourne True. Autrement dit :
— La fonction filter(f, L) a besoin d’une fonction f comme premier argument.
— f doit retourner une valeur booléenne, soit Vrai ou Faux.
— Cette fonction sera appliquée à tous les éléments de la liste L.
3.4 Exercices 59

— Seulement les éléments où la fonction f retourne Vrai seront produites par l’itérateur,
qui est la valeur de retour de filtre (fonction, séquence).
Par exemple, filter(lambda x : x%3, range(20)) renvoie la liste :

[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19]


la fonction zip()
Synatxe de la fonction zip() est le suivant :
syntaxe de zip()
zip(*iterables)

Cette fonction permet de prendre zéro ou plusieurs objets itérables et retourne un


itérable contenant des tuples où chaque tuple contient un élément de chaque objet itérable.
L’exemple qui suit permet de renvoyer le dictionnaire : {’Ahmed’ : 10.5, ’Nissrine’ : 12.25,
’Ali’ : 8.75} :
exemple d’utilisation de zip()

notes = [10.50 , 12.25 , 8.75]


s t u d e n t s = [ ’Ahmed ’ , ’ N i s s r i n e ’ , ’ A l i ’ ]

r e s u l t = zip ( students , notes )


result = dict ( result )
print ( result )

La fonction zip() retourne un itérateur de tuples de type zip qu’on peut le convertir en
liste, dictionnaire, tuple ou un set :
— Si on passe zéro arguments, zip() retourne un itérateur vide ;
— Si on passe un seul itérateur, zip() retourne un itérateur de tuples où chaque tuple
contient uniquement un seul élément ;
— Si on passe plusieurs itérateur, zip() retourne un itérateur de tuples où chaque tuple
contient des éléments de tous les itérateurs
— Supposons qu’on a passé deux itérateurs à la fonction zip() où le premier contient
trois éléments et le seconde contient cinq éléments. Alors, zip() retourne un itérateur
contenant uniquement trois tuples car zip va s’arrêter quand l’itérateur de taille
minimale pointe vers sa fin.

3.4 Exercices
Exercise 3.1 On veut réunir dans un programme python "ma_bibliothque.py" un certain
nombre des outils mathématiques bien connus pour faciliter l’utilisation. Pour cela, on
définit d’abord pour chaque outils une fonction qui réalise la tâche de l’outil. Ensuite,
on définit un menu qui permet l’accès aux outils. Selon le choix d’outils, on propose les
saisies de données adéquates et exécute la fonction correspondante et affiche le résultat.
Écrire ce programme et proposer pour cet exercice les fonctions suivantes :
1. valeurabsolue(x) : retourne la valeur absolue d’un nombre réel x
60 Chapitre 3. La démarche d’analyse descendante
2. puissance(x, n) : calcule xn , n peut être 0, < 0 ou > 0.
3. factorielle(n) : calcule n! (factoriel de n = 1 ∗ 2 ∗ ... ∗ (n − 1) ∗ n , n ≥ 0)
4. estpair(n) : retourne True si n est pair, False sinon
5. estimpair(n) : retourne True si n est impair, False sinon
6. diviseurs(n) :affiche les diviseurs de n
7. nombrediviseurs(n) : retourne le nombre de diviseurs de n
8. estpremier(n) : retourne True si n est premier, False sinon.
9. pgcd(a, b) : retourne le plus grand diviseur commun de a et de b.
10. premiers2(a, b) : retourne True si a et b sont premiers entre eux, False sinon
11. ppcm(a,b) : retourne le plus petit commun multiple de a et b
12. racinecarrée(x, eps) : retourne la racine carrée d’un réel positif x avec la précision
eps selon l’algorithme suivante : à partir d’un nombre aléatoire y0 , calculer
y1 = 12 (y0 + yx0 ) :
— Si |y1 − y0 | ≥ 0 alors recalculer y1 en fixant que y0 = y1 ,
— Sinon, arrêter les calcules
la valeur absolue de x est la dernière valeur de y1 calculée. (ceci permet de
programmer la limite de la suite (Un ) (limUn ) où (Un+1 = 12 (Un + Uxn ))
13. équation1(a,b) retourne la solution de l’équation de premier degré ax + b = 0
14. équation2(a,b,c) retourne la solution de l’équation de deuxième degré ax2 + bx +
c=0

Exercise 3.2 Nous considérons dans tout l’exercice des listes d’entiers de taille 20 avec
des doublons.

Première partie :

En utilisant la démarche d’analyse descendante, écrivez un programme Python qui :


1. déclare deux listes l_pair et l_impair vides où des entiers pairs et impairs non nuls
peuvent être enregistrés respectivement.
2. demande à l’utilisateur de saisir des entiers et de les insérer dans une des deux
listes l_pair et l_impair correspondantes. La saisie se terminera lorsque les deux
listes sont remplies entièrement (chaque liste contiendra exactement 20 entiers).
3. affiche le contenu de chaque liste en utilisant une boucle for.
4. calcule et affiche la moyenne des entiers de chaque liste.
5. affiche le nombre d’entiers strictement supérieurs, strictement inférieurs et égaux
à la moyenne pour chaque liste. L’exécution de votre programme devra donner
un affichage sur écran semblable à l’exemple ci-dessous :
3.4 Exercices 61

Contenu de la liste l_pair :


l_pair[0] = 2
l_pair[1] = 4
l_pair[2] = 2
l_pair[3] = 16
l_pair[4] = 8
...
Contenu de la liste l_impair :
l_impair[0] = 3
l_impair[1] = 1
l_impair[2] = 5
l_impair[3] = 9
...
Moyenne des entiers de l_pair est : 18
Moyenne des entiers de l_impair est : 13.5
l_pair possède:
12 entiers strictement supérieurs à 18;
6 entiers strictement inférieurs à 18;
2 entiers ´egaux à 18
l_impair possède:
13 entiers strictement supérieurs à 13.5;
7 entiers strictement inférieurs à 13.5;
0 entiers égaux à 13.5

Deuxième partie :

Nous considérons les deux listes l_pair et l_impair remplies précédemment. Écrivez
un programme Python qui :
1. calcule et affiche le plus grand entier pair de la liste l_pair.
2. calcule et affiche le plus grand entier impair de la liste l_impair.
3. calcule et affiche le plus grand des entiers pairs et impairs. L’exécution de
votre programme devra donner un affichage sur écran semblable à l’exemple
ci-dessous :
Le plus grand des entiers pairs est : 22
Le plus grand des entiers impairs est : 35
Le plus grand des entiers pairs et impairs est : 35

Troisième partie :

Nous considérons les mêmes listes précédentes l_pair et l_impair. Écrivez un pro-
gramme Python qui :
62 Chapitre 3. La démarche d’analyse descendante
1. calcule pour chaque entier de l_pair son nombre d’entiers appartenant à la liste
l_impair strictement supérieurs. On évitera les affichages redondants. L’exécution
de votre programme devra donner un affichage sur écran semblable à l’exemple
ci-dessous :
3 entiers impairs sont strictement supérieurs à 2 ;
4 entiers impairs sont strictement supérieurs à 4 ;
2 entiers impairs sont strictement supérieurs à 16 ;
...

NB : il est formellement interdit d’utiliser les fonctions prédéfinies sur les listes telles
que max(l), print(l), etc. où l est une liste quelconque. ■

Exercise 3.3 On désire écrire un programme qui calcule et affiche les résultats obtenues
par les N étudiants qui se sont présentés à un concours.
Il y a 8 matières au programme du concours (français, informatique, math, etc.), et,
pour le concours, les étudiants passent une épreuve par matière.
Chaque épreuve est notée sur 20 et pondérée par un coefficient (par exemple : le
français a pour coefficient 3 et l’informatique a pour coefficient 5). Pour chaque étudiant,
le calcul de la moyenne qu’il a obtenue au concours se fera donc à partir de ses notes et
des coefficients qui pondèrent les matières.
Les étudiants sont numérotés de 0 à N-1. Les matières sont numérotées de 0 à 7.
Les coefficients des 8 matières sont enregistrés dans la variable coeff, qui est une
liste de 8 entiers tel que coeff[i] est le coefficient de la matière i.
Les notes obtenues par les étudiants sont enregistrées dans la liste list_notes, liste
de réels de dimensions 2 et de taille N × 8, tel que la variable list_notes[e][i] contient la
note obtenue par l’étudiant numéro e à la matière numéro i.
Par ailleurs, on utilisera aussi (voir la question 6) dans le programme tab_moyennes,
de type liste de réels de taille N, dans lequel on enregistrera les moyennes des étudiants :
la variable tab_moyennes[e] contiendra la moyenne que l’étudiant numéro e a obtenue
au concours.
les trois listes coeff, list_notes et tab_moyennes seront des variables globales du
programme.

Première partie
Le but de cette partie est d’écrire quelques fonctions qui seront utilisées dans la
deuxième partie. Il est formellement interdit d’utiliser les fonctions prédéfinies sur les
listes telles que max(l), print(l), etc. où l est une liste quelconque.

Question 1 :

Écrire la fonction somme_list(l) qui calcule et renvoie la somme des éléments d’une
liste l de nombres.
3.4 Exercices 63
Question 2 :

Écrire la fonction max_list(l) qui calcule et renvoie l’index de la valeur maximale


contenue dans la liste l.

Question 3 :

Soit x une variable float, qui contient une note comprise entre 0 et 20. On désire
écrire une fonction max_list(l) qui calcule et renvoie la valeur de x arrondie au demi-
point supérieur.
On rappelle que l’instruction y = int(x) affecte à y la valeur entière de x.
Le calcule de la valeur de x arrondie au demi-point supérieur se fait de la façons
suivante :
— si x est égale à int(x), la valeur arrondie est x ;
— si x- int(x) est inférieur ou égale à 0.5, la valeur arrondie est int(x)+0.5 ;
— si x- int(x) est supérieur ou égale à 0.5, la valeur arrondie est int(x)+1 ;
Écrire la fonction arrondie (x) qui calcule et renvoie la valeur arrondie de x

Deuxième partie
Question 4 :

Le nombre N d’étudiants inscrit au concours est 350. Écrire la définition de


la constante N et la déclaration en variables globales des listes coeff, list_notes et
tab_moyennes.

Question 5 :

Écrire la fonction meilleur_note(m) qui calcule et renvoie la meilleur note qui a été
obtenue dans la matière m par l’ensemble des étudiants.

Question 6 :

On désire calculer les moyennes que les étudiants ont obtenues au concours, les
arrondir au demi-point supérieur, puis les enregistrer dans la liste tab_moyennes.
Pour cela, écrire la fonction calculer_moyenne() qui :
1. calcule la somme des coefficients (utilisez la fonction somme_list(l) de la première
partie)
2. pour chaque étudiant :
— calculer la somme de ses notes pondérées par les coefficients ;
— calcule sa moyenne ;
— arrondit cette moyenne au demi-point supérieur ;
— enregistre dans la liste tab_moyennes cette valeur arrondie de la moyenne,

Question 7 :

A partir des données contenues dans la liste tab_moyennes ; on désire afficher les
moyennes obtenues au concours, sous la forme suivante, avec une précision d’une
64 Chapitre 3. La démarche d’analyse descendante
décimale pour la moyenne :

Étudiant numéro 0 : moyenne = 12.5


Étudiant numéro 1 : moyenne = 9.0
Étudiant numéro 2 : moyenne = 14.5
....

Ecrire la fonction afficher_moyenne qui affiche la liste des moyennes selon le format
ci-dessus.

Question 8 :

On suppose que l’on dispose d’une fonction saisir_note() qui permet de remplir la
liste list_notes.
Ecrire la fonction main() qui, en appelant les fonctions précédentes, permet de :
— saisir les notes,
— pour chaque matière, affiche à l’écran la meilleur note qui a été obtenue dans
cette matière,
— calculer toutes les moyennes et les afficher.

Question 9 :

On désire maintenant faire à l’écran un affichage des résultats par ordre de mérite,
sous la forme suivante :

Étudiant numéro 322 : moyenne = 17.5


Étudiant numéro 81 : moyenne = 17.0
Étudiant numéro 28 : moyenne = 16.5
....

En appliquant l’algorithme de tri par sélection, écrire une fonction afficher_merite()


qui fait l’affichage demandé. (on peut utiliser la fonction max_list () de la première
partie ■
4. Pile et File

Dans ce chapitre, nous étudions deux structures des données : Les piles et les files.
Ces deux structures jouent un rôle très important non seulement dans la conception
et la programmation des applications modernes mais aussi en informatique elle même,
notamment dans la gestion de mémoire, la programmation de compilateur pour la correction
syntaxique de code source et dans l’exécution des fonctions récursives, etc.
Le but, donc, de ce chapitre est de décrire les représentations des structures de données
telles : les piles et les files. L’autre but recherché est de voir l’importance de ces structures
à travers quelques exemples d’applications.

4.1 Pile
[9] Quand on parle d’une structure de données on parle d’une organisation logique des
données permettant de simplifier ou d’accélérer leur traitement.
Definition 4.1.1 — pile. Une pile est une structure de données qui suit le principe
dernier entré est le premier à servir (Ou LIFO pour Last In - First Out ).

Elle correspond exactement à l’image traditionnelle d’une pile de cartes ou d’assiettes


posée sur une table. En particulier, on ne peut accéder qu’au dernier élément ajouté, qu’on
appelle le sommet de la pile. Ainsi, si on a ajouté successivement A, puis B, puis C dans
une pile, on se retrouve dans la situation suivante :

C est empilé sur B, lui-même empilé sur A. On peut soit retirer C de la pile (on dit qu’on «
66 Chapitre 4. Pile et File

dépile » C), soit ajouter un quatrième élément D (on dit qu’on « empile » D). Si on veut
accéder à l’élément A, il faut commencer par dépiler C, puis B.
Cette structure est utile quand-t-on veut stocker (archiver) des éléments (programmes,
fichiers, processus, données simple (int, float, str, bool, ...), etc.) dans un ordre bien précis
de telle façon à cacher ses éléments sauf l’élément qui est au sommet. Le seul élément
qu’on peut extraire de la liste et celui qui se trouvent au sommet. dans le cas où on veut
extraire les autres, il suffit, donc, les parcourir en utilisant une boucle for ou while.
L’exemple traditionnel de l’utilisation d’une pile est celui d’un navigateur web. Une
pile sert à mémoriser les pages Web visitées. L’adresse de chaque nouvelle page visitée
est empilée et l’utilisateur dépile l’adresse de la page précédente en cliquant le bouton "
Afficher la page précédente".
Le deuxième exemple est la mémorisation des caractères(ou les actions) tapés par
l’utilisateur dans un Texteur (Microsoft word, gedit, Bloc Note, ...). La fonction "Annuler la
frappe" (en anglais "Undo" ou ctrl+z) d’un traitement de texte mémorise les modifications
apportées au texte dans une pile. Et à chaque fois que vous annuler une opération, le
logiciel dépile le sommet.
Le troisième exemple est la pile de vérification de la correction des parenthèses d’une
chaîne de caractères. Nous traitons cet exemple une fois on a implémenté la structure pile
en python.

4.1.1 Opérations de base caractérisant une Pile


Avant de voir comment va-t-on réaliser la structure d’une pile en Python, il faut définir
les opérations de base qui définissent une telle structure de données.
La première opération consiste à créer la pile et ses éléments initiales (la structure, le
sommet, la capacité maximale). Une fois la pile est crée, On définit les deux opérations
qui permettent d’ajouter(Empiler) et de retirer (Dépiler) un élément de celle-ci. Les trois
opérations de base sont :
— Créer_pile(c) : Cette fonction renvoie une pile p de capacité c
— Empiler(e,p) : renvoie None si l’opération d’ajout de l’élément e est passée sans
problème et une erreur en cas d’échec .
— Dépiler(p) : renvoie l’élément à dépiler si la pile n’est pas vide
D’autre opérations sont disponible, mais ne modifie pas la pile
— est_vide(p) : renvoie True si la pile est vide et False sinon
— est_pleine(p) : renvoie True si la pile est pleine et False sinon
— Sommet(p) : renvoie la partie visible de la pile : Le sommet
Une chose très important à souligner ici est le choix de la structure permettant de stocker
les données de la pile. La manière la plus simple de réaliser une pile consiste à utiliser un
tableau ou une liste de taille N.

En python, le type de données permettant de réaliser une pile est la structure(ou la


classe) List, et on distingue deux types de pile :
— Pile à capacité finie
— Pile non bornée
4.1 Pile 67

4.1.2 Piles à capacité finie


Créer une pile
La première opération à définir est la fonction permettant de créer une nouvelle pile de
capacité c. Nous allons réserver le premier élément de la liste p pour stocker sa capacité
réelle.
def cr é e r _ p i l e ( c ) :
p = ( c + 1 ) * [ None ]
p [O] = 0
return p

création de la pile
À la création, la pile contient 0 élément (p[0]=0). Après les opérations d’ajout et de retrait,
cette capacité va être incrémenter ou décrémenter de telle façon de ne pas dépasser sa
capacité maximale c puisqu’on parle d’une pile à capacité finie.
Une fois fait, on ne peut pas appliquer les méthodes classiques agissant sur les listes
telles que : append et pop car elles modifient la structure(la taille qu’on a appelée capacité
c ) de notre liste. La seule opération autorisée est len(p) qui renvoie la capacité c maximale
de notre pile. p[0] va servir de la taille réelle de notre pile (nombre d’éléments insérés).

Empiler un élément :

La deuxième opération à définir, une fois la pile est crée, est la fonction qui permet
d’empiler un élément e dans une pile p :
def empiler (p , e ) :
n = p [0]
a s s e r t n < l e n ( p ) −1
n +=1
p [0] = n
p[n] = e

Fonction empiler
Avant d’empiler, il faut extraire l’information qui indique sa taille réelle n. Si la taille n est
strictement inférieur à sa capacité maximale c= len(p) et qu’il reste au moins une place
pour l’élément e (< len(p) -1) alors dans ce cas on peut empiler e au sommet n+1 car le
dernier élément avant d’empiler e se trouve à l’indice n. Dans le cas où la pile est pleine
(le sommet se trouve à l’indice len(p)-1) on ne peut pas ajouter des éléments afin de ne pas
avoir le problème de débordement(dépassement de capacité ou overflow en anglais).

R Attention : à chaque opération d’ajout(empiler), il faut mettre à jour les méta-données


de la pile (sa taille réelle : ici c’est l’indice de l’élément qui est au sommet).

Dépiler un élément :
La troisième opération à définir est celle qui permet de dépiler un élément d’une pile p.
Le seul élément qu’on peut dépiler est celui au sommet (loi LIFO :last in first out) :
def d e p i l e r ( p ) :
n = p [0]
68 Chapitre 4. Pile et File

a s s e r t n >0
p [ 0 ] = n −1
return p [0]

Listing 4.1 – dépiler le sommet

Nous commençons le traitement par l’instruction qui nous indique la capacité réelle de la
pile(n = p[0]). Il faut ensuite s’assurer que la pile n’est pas vide sinon rien à dépiler (assert
n>0). Enfin,et avant de renvoyer l’élément à dépiler, il faut mettre à jour la taille réelle de
la pile p (p[0] = n-1).
Cependant, pour ne pas avoir une erreur d’assertion, on peut afficher le message ’under
low’ si la pile est vide.
def d e p i l e r ( p ) :
n = p [0]
i f n ==0:
p r i n t ( " E r r e u r : underFlow " )
else :
data= p[n]
p [ n ] = None
n=n −1
p [0] = n
return data

Listing 4.2 – dépiler le sommet

Autre opérations

def taille_max ( p ) :
return len (p)

Listing 4.3 – taille maximale d’une pile

def t a i l l e _ r e e l l e ( p ) :
return p [0]

Listing 4.4 – taille maximale d’une pile

def est_vide ( p ) :
r e t u r n t a i l l e _ r e e l l e ( p ) ==0

Listing 4.5 – prédicat pour tester si pile est vide

def e s t _ p l e i n e ( p ) :
r e t u r n t a i l l e _ r e e l l e ( p ) == t a i l l e _ m a x ( p )

Listing 4.6 – prédicat pour tester si pile est pleine


4.1 Pile 69

4.1.3 Piles non bornées


Avantage et inconvénient :
Un des défauts de l’implémentation précédente est sa capacité bornée. Avec cette
limitation de taille, on fixe le nombre maximal d’opérations qui sont autorisées à empiler
dans une pile. L’avantage est évidement une application bien alléger en terme de l’espace
mémoire utilisé.
On présente ici une autre manière de réaliser une pile : Pile non bornée. Elle exploite
une propriété des tableaux indexés(list) en Python qu’on n’a pas encore utilisée, à savoir la
possibilité d’ajouter ou de supprimer des éléments.
Le type de données List en Python possède des méthodes qui permettent de :
— Empiler : Ajouter un élément à la fin de la liste : append
— Dépiler : Renvoyer et supprimer le dernier élément : pop
— Savoir l’indice de sommet : len(p)-1
Voici ci-dessous une implémentation d’une pile non bornée :

Créer une pile vide

def cr é e r _ p i l e ( ) :
return []

Listing 4.7 – créer une pile non bornée

Empiler

def empiler (p , e ) :
p . append ( e )

Listing 4.8 – fonction empiler

Dépiler

def d e p i l e r ( p ) :
a s s e r t l e n ( p ) >0
r e t u r n p . pop ( )

Listing 4.9 – fonction dépiler

Autre fonctions
fonction prédicat pour tester si la pile est vide
def est_vide ( p ) :
r e t u r n l e n ( p ) == 0

fonction prédicat pour tester si la pile est pleine


def t a i l l e ( p ) :
return len (p)
70 Chapitre 4. Pile et File
4.1.4 Exercice d’application
Exercise 4.1 Nous voulons écrire un programme en python permettant de vérifier qu’un
mot est bien parenthésé. Ainsi, ce programme doit :
— accepter les mots comme (), ()(()) ou ((()())()) ;
— rejeter les mots comme )(, ()(() ou ((()()))).
Le programme doit commencer par la lecture d’une chaîne au clavier. Puis, il doit
analyser, un par un, les caractères de la chaîne. Ainsi, Pour chacun des caractères de la
chaîne :
— si c’est une parenthèse ouvrante ’(’, une valeur est empilée ;
— si c’est une parenthèse ’)’ fermante, une valeur est dépilée.
Le mot est accepté si :
— la pile n’est jamais vide à la lecture d’une fermante ; et si
— la pile est vide lorsque tout le mot a été analysé.

Le code Python qui suit permet de vérifier si un mot est bien parenthésé ou non :
def bienParenthese ( s ) :
p = creer_pile ()
for i in range ( len ( s ) ) :
i f s [ i ]== ’ ( ’ :
empiler (p , s [ i ])
e l i f s [ i ]== ’ ) ’ :
if est_vide (p) :
return False
depiler (p)
else :
continue
return est_vide (p)

Listing 4.10 – Solution

E = i n p u t ( " E n t r e r une e x p r e s s i o n math é m a t i q u e c o n t e n a n t d e s p a r e n t h è s e s


:")
i f bienParenthese (E) :
p r i n t ( E+ " e s t une e x p r e s s i o n b i e n p a r e n t h é s é e s " )
else :
p r i n t ( E+ " n ’ e s t p a s une e x p r e s s i o n b i e n p a r e n t h é s é e s " )

Listing 4.11 – Test de la fonction bienParenthese


voici un exemple d’exécution :
4.2 Files 71

4.2 Files
4.2.1 Notion de File
Definition 4.2.1 — File. Une file[9] est une structure de données dynamique dans
laquelle on insère des nouveaux éléments à la fin (queue) et où on enlève des éléments
au début (tête de file). La file est basée sur le principe "Premier entré est le premier à
servir", on parle de mode d’accès FIFO (First In, First Out), par opposition au mode
d’accès LIFO (Last In First Out ) des piles.

Le fonctionnement ressemble à une file d’attente : les premières personnes à arriver sont
les premières personnes à sortir de la file. Une file est modifiée à ses deux bouts :

4.2.2 Opérations de base caractérisant une File


Voici les opérations de bases utilisées pour manipuler des files :
— FileVide : créer une file vide
— EstVide : indique si la file est vide ou non ;
— Enfiler : ajouter un élément à la fin de la file ;
— Tête : consulter l’élément à la tête de la file ;
— Queue : consulter l’élément en fin de file ;
— Défiler : retirer l’élément en tête de file.

4.2.3 Réalisation d’une structure File


En Python, les files peuvent toutes être simulées avec la liste. Pour ajouter un élément
à la fin de la file, utiliser append(). Pour récupérer un élément du devant de la file, utiliser
pop(0) avec 0 est l’indice du premier élément :
def FileVide ( ) :
return []

def E n f i l e r ( f , e ) :
f . append ( e )

def D e f i l e r ( f ) :
a s s e r t l e n ( f ) >0
r e t u r n f . pop ( 0 )

def EstVide ( f ) :
r e t u r n f ==[]

def Tete ( f ) :
72 Chapitre 4. Pile et File

return f [0]

d e f Queue ( f ) : s
r e t u r n f [ l e n ( f ) −1]

Listing 4.12 – implémentation d’une file en python

4.3 Exercices
Exercise 4.2 Écrire une fonction copier_pile(p) qui prend en argument une pile p et
retourne une copie de p sans modifier p. ■

Exercise 4.3 Écrire une fonction inverser_pile(p) qui prend en argument une pile p et
retourne une autre pile dont les éléments sont les éléments de p dans l’ordre inverse, p
n’est pas modifiée. ■

Exercise 4.4 On dispose d’une structure de pile à laquelle sont associées les seules
opérations ou fonctions de base : creer_pile(p), empiler(p), sommet(p), depiler(p),
est_vide(p).
Le but est de construire les opérations suivantes à l’aide de ces éléments :
1. Une fonction depilerK(p,k) qui dépile k éléments si la pile p en contient au moins
k et dépile toute la pile sinon sans lever d’erreur.
2. Une fonction depilerJusqu(p,e) qui dépile p tant que l’élément e n’est pas rencon-
tré ou p n’est pas vide.
3. Une fonction perm2(p) qui permute dans p, le sommet et le terme suivant.
4. Une fonction rot(p,k) qui réalise une permutation circulaire sur les k éléments
premiers éléments de la pile.

Exercise 4.5 La notation polonaise inversée est une façon d’écrire les expressions
arithmétiques sans indiquer de multiples parenthèses. Une expression arithmétique
écrite en notation polonaise inversée est une suite de nombres et d’opérateurs (+, -, / ou
*) et se lit (et s’évalue) de gauche à droite de la façon suivante :
— lorsqu’un nombre est lu, il est empilé sur une pile (initialement vide)
— lorsqu’un opérateur est lu, les deux premiers éléments de la pile sont récupérés et
dépilés, l’opération est effectuée sur les deux valeurs obtenues, et le résultat est
empilé ;
— le résultat de l’expression est le premier (et normalement le seul) élément de la
pile à la fin de la lecture.
Notre objectif est d’implémenter cette méthode en un programme python :
1. Appliquer la méthode exposée pour calculer : 17 10 - , 3 28 7 / + et 3 28 + 7 /
Comment s’écrivent ces expressions en notation classique ?
2. Traduire en notation polonaise inversée les expressions suivantes : (19 * 6) - 7 et
(4 - 2 * (7 + 6)) + 3 * 5
4.3 Exercices 73

3. Écrire une fonction qui évalue une expression polonaise inversée, composée
d’entiers entre 0 et 9 et des quatre opérations élémentaires. On pourra par exemple
suivre les étapes suivantes :
— une fonction qui prend en entrée un caractère et renvoie vrai s’il s’agit d’une
opération élémentaire et faux sinon,
— une fonction qui prend un symbole-opération et deux entiers et qui renvoie
le résultat de l’opération,
— enfin, la fonction d’évaluation.
4. testez la fonction pour calculer : 17 10 - , 3 28 7 / + et 3 28 + 7 /

II
Les structures de données
non linéaires

5 Dict et Set . . . . . . . . . . . . . . . . . . . . . . . . . 77
5.1 Présentation
5.2 Fonction de hachage
5.3 Les tableaux associatifs : dict
5.4 Les ensembles : set
5.5 Pile implémenté par un dictionnaire
5.6 Conclusion
5.7 Exercices
5. Dict et Set

5.1 Présentation
Dans ce chapitre, nous présenterons deux structures de données non linéaires : les
dictionnaires et les ensembles. Nous présenterons également le concept de base derrière
ces deux structures : fonctions de hachage.

5.2 Fonction de hachage


5.2.1 Le hash
Une fonction de hachage est une fonction mathématique qui prend en entrée une donnée
de taille quelconque (par exemple, une chaîne de caractères ou un nombre) et la transforme
en une valeur numérique ou alphanumérique de taille fixe appelée "hash".
La fonction de hachage est conçue pour être rapide à calculer, et pour que deux entrées
différentes ne donnent jamais le même hash. Autrement, pour deux entrées différentes x et
y, la fonction renvoie deux sorties différentes.

∀x ̸= y ⇒ f (x) ̸= f (y)

Dans ce cas (f est injective), on dit que la fonction est sans collision. Il est important
de choisir une fonction de hachage sécurisée, car il existe des attaques pour trouver des
collisions, ce qui peut compromettre la sécurité de vos données.
Les fonctions de hachage sont utilisées dans de nombreux domaines, tels que la sécurité
informatique (par exemple, pour stocker des mots de passe sécurisés), la compression
de données (par exemple, pour trouver rapidement des doublons dans les données) et les
structures de données telles que les tables de hachage (où les entrées sont stockées en
fonction de leur hash). Les fonctions de hachage couramment utilisées sont : SHA-256,
SHA-512 et MD5.
78 Chapitre 5. Dict et Set

5.2.2 Table de hachage


Une table de hachage est une structure de données qui permet de stocker des entrées en
les indexant à l’aide de leur valeur de hash. Chaque entrée est associée à une clé unique,
et la table de hachage utilise une fonction de hachage pour calculer la position (index) à
partir de la valeur d’entrée (key). Les entrées sont ensuite stockées dans une case de la
table correspondant à leur clé key.

F IGURE 5.1 – une table de hachage

Les tables de hachage sont souvent utilisées pour implémenter des dictionnaires ou des
ensembles en informatique, car elles permettent un accès rapide aux entrées en utilisant
leur clé. Les tables de hachage sont particulièrement utiles pour les opérations d’insertion,
de suppression et de recherche, car elles peuvent être effectuées en temps constant en
moyenne (par opposition à un temps de recherche linéaire pour les listes simples).
Ainsi, on réserve un tableau de taille fixe et on stocke les données dans une case
correspondant à son hash. Pour insérer le contact (’ali’, ’+212610040608’, on calcule le
hash de la clé =’ali’ (f(’ali’)=2) et on stocke le couple (’ali’, ’+212610040608’) dans la
case d’index 2(figure 1).
Cependant, les tables de hachage peuvent également être sujettes à des collisions, où
plusieurs entrées différentes produisent le même hash. Pour éviter les collisions, il est
important de choisir une fonction de hachage efficace qui distribue uniformément les
entrées dans les différentes cases de la table.
Les fonctions de hachage sans collision sont utilisées pour assigner un code numérique
unique à chaque élément d’une structure de données, telle qu’un dictionnaire. Voici
quelques exemples de fonctions de hachage simples :
1. Fonction de hachage de somme : elle consiste à additionner les codes ASCII de
chaque caractère d’une chaîne de caractères pour obtenir un code de hachage unique.
Par exemple, pour la chaîne ’hello’, la fonction de hachage serait 104 + 101 + 108 +
108 + 111 = 532.
5.3 Les tableaux associatifs : dict 79

2. Fonction de hachage de multiplication : cette fonction consiste à multiplier chaque


code ASCII d’une chaîne de caractères par un nombre primaire. Par exemple, pour
la chaîne ’hello’, la fonction de hachage pourrait être 104 ∗ 101 ∗ 108 ∗ 108 ∗ 111 =
7438790400.
3. Fonction de hachage de rotation : cette fonction consiste à effectuer une opération de
rotation sur les codes ASCII des caractères d’une chaîne de caractères. Par exemple,
pour la chaîne ’hello’, la fonction de hachage pourrait être (104 << 1) + (101 <<
2) + (108 << 3) + (108 << 4) + (111 << 5) = 2049369601.
4. Fonction de hachage de réduction modulo : cette fonction consiste à effectuer une
opération de somme sur les codes ASCII des caractères d’une chaîne de caractères,
puis à prendre le modulo d’un nombre fixe pour obtenir un code de hachage unique.
Par exemple, pour la chaîne ’hello’ et un modulo de 10, la fonction de hachage serait
(104 + 101 + 108 + 108 + 111)%10 = 9
5. Fonction de hachage de DJB2 : c’est une fonction de hashage populaire pour les
chaînes de caractères. Elle consiste à effectuer une opération de multiplication et
d’addition sur les codes ASCII des caractères d’une chaîne de caractères pour obtenir
un code de hachage unique.
6. Fonction de hachage de murmur3 : cette fonction de hachage est une fonction de
hashage moderne pour les données de longueur variable. Elle utilise une combinaison
de techniques de rotation et de masquage pour minimiser les collisions et améliorer
la distribution des codes de hachage.
7. Fonction de hachage SHA-256 : cette fonction de hachage est une fonction de
hashage sécurisée pour les données de longueur variable. Elle utilise une algorithme
de hachage cryptographique pour produire un code de hachage unique pour chaque
entrée.

5.3 Les tableaux associatifs : dict

Les dictionnaires sont des structures de données qui permettent de stocker des paires
clé-valeur. Les clés sont uniques dans un dictionnaire et permettent de retrouver la valeur
associée.

5.3.1 Définition et Création

Définition d’un dictionnaire : dict


Collection de couples clé :valeur entourée d’accolades ”” et ”” et séparés par virgule
”,” :
80 Chapitre 5. Dict et Set

Création d’un dictionnaire


>>> # première méthode
>>>dict_1={
’chat’:’cat’,’chien’:’dog’,’oiseau’:’bird’,’cow’:’vache’
}
>>> # deuxième méthode
>>> dict_2=dict(mouche=’fly’,cheval=’horse’,abeille=’bee’)

>>> # troisième méthode:


>>> dict_3 ={}
>>> dict_3[’papillon’] = ’butterfly’
>>> dict_3[’taureau’] = ’bull’
>>> dict_3[’singe’] =’monkey’

>>> # quatrième méthode: par compréhension


>>> d1 = {x:x**3 for x in range(10)}
>>> type (d1)
<class, ’dict’>
>>> d1
{0: 0, 1: 1, 2:8, 3:27, 4:64, 5:125, 6:216, 7:343, 8:512, 9:729}

5.3.2 Accès aux données et opérations


Contrairement aux listes, l’accès à une donnée du dictionnaire se fait à l’aide d’une
clé :
>>> # Accès à la valeur d’une clé dans le dictionnaire
>>> print(dict_1[’cow’])
vache

>>> # ou encore
>>> dict_1.get(chien)
dog

>>> # Modification d’une valeur dans le dictionnaire


>>> dict_example[’key1’] = ’new_value1’

>>>#si la clé n’existe pas,la modification devienne une insertion


>>> dict_2[’grenouille’] = ’frog’
>>> dict_2
{’mouche’:’fly’,’cheval’:’horse’,’abeille’:’bee’,’grenouille’:’frog’}

Les clés, dans un dictionnaire sont uniques et peuvent être définies par des objets
immuables (str, int, float, tuple, ...). les listes sont mutables et, donc, ne peuvent pas être
utilisées comme des clés. La raison est très simple : au moment de la création d’un couple
(liste :valeur) on calcule le hash de cet objet liste et on le stocke dans sa case mais si on
5.3 Les tableaux associatifs : dict 81

modifie cet objet on risque de trouver un autre hash et on perd l’association list :valeur.
Ainsi, Python génère une erreur de type unhashable type

>>> d={[1,2,3]:’un deux trois’}


TypeError: unhashable type: ’list’

Les dictionnaires sont des objets modifiables dans le sens où on peut modifier la valeur
d’une clé. Toute modification d’une valeur associée à une clé qui n’existe pas impliquera
sa création. On peut également supprimer des clés :

>>> # suppression via l’opérateur del


>>> del dict_2[’cheval’]

>>> # ou encore via pop qui renvoie la valeur supprimée


>>> abeille_en_fr = dict_2.pop(’abeille’)
>>> abeille_en_fr
’bee’
>>> dict_2
{’mouche’:’fly’,’cheval’:’horse’,’grenouille’:’frog’}

>>> # ou encore supprimer un couple clé,valeur via la loi LIFO


>>> # Last in First out et renvoie une erreur si elle est vide
>>> dict_2.popitem() # a tester vous même

Les dictionnaires possèdent d’autres méthodes, à savoir :


82 Chapitre 5. Dict et Set

>>> # tester l’existence d’une clé


>>> ’cheval’ in dict_2
True

>>> # liste de clés


>>> dict_2.keys()
dict_keys([’mouche’,’cheval’,’abeille’,’grenouille’])

>>> # liste de valeurs


>>> dict_2.values()
dict_values([’fly’, ’horse’, ’bee’, ’frog’])

>>> # liste de couples clé,valeur


>>> dict_2.items()
dict_items([(’mouche’,’fly’),(’cheval’,’horse’),(’abeille’,’bee’),
(’grenouille’, ’frog’)])

>>> # mettre à jour d’un dictionnaire à partir d’un autre (union)


>>> dict_2.update(dict_3)

>>> # vider un dictionnaire


>>> dict_3.clear()

>>> # faire une copie indépendante


>>> animaux = dict_2.copy()

Les dictionnaire sont itérables : on peut parcourir les données d’un dictionnaire via la
liste de ses clés (par défaut) :

>>> # Explorer un dictionnaire


>>> for animal_en_fr in dict_2:
... print (f"{animal_en_fr}:={dict_1[animal_en_fr]}")

chat:= cat
chien:= dog
oiseau:= bird
cow:= vache

5.3.3 Un mini-projet : gestion de contacts


Les dictionnaires et les listes peuvent êtres définies comme des valeurs dans un autre
dictionnaires et réciproquement une liste peut avoir un dictionnaire comme valeur. En
d’autres termes, on peut imbriquer les dictionnaires de la même manière d’imbriquer les
listes.
Pour bien comprendre cette imbrication rien n’est simple qu’un exemple : on va créer
5.3 Les tableaux associatifs : dict 83

un mini-projet permettant de gérer les contacts d’un répertoire téléphonique. On choisira


comme conteneur un dictionnaire contacts défini comme variable globale.

La structure de stockage contacts :

les clés (keys) dans contacts sont les noms des personnes et les valeurs sont les
informations associées à ces personnes. On se limite aux informations suivantes : last_name,
birthday, birthplace, email et phonenumber. Ces informations vont être stockées dans un
autres dictionnaire values. Par exemple, le contact ’ElIbrahimi’ aura la forme suivante :

contacts = {
’ElIbrahimi’:
{
’last_name’ : ’Ali’ ,
’birthday’ : ’2001-12-25’ ,
’birthplace’: ’Beni Mellal’ ,
’email’ : ’ali.ibrahimi@abc.net’,
’phonenumber: ’+212610579864’
}
}

Les primitives de base :

notre objectif, dans ce mini-projet, est de pouvoir gérer les contactes, c’est à dire
ajouter, modifier, supprimer et rechercher un contact. Nous commençons, donc, par la
définition et la création de ces primitives(fonctions) :
84 Chapitre 5. Dict et Set

def add(key, values):


contacts[key] = values
print ("a contact has been added successfuly")

def remove(key):
if key in contacts:
del contacts[key]
print("a contact has been removed successfuly")
else:
print(contact,key, "not found")

def find(name):
found = []
for key in contacts:
if name in key:
found.append(key)
return found

def get_one(name):
return contacts[name] if name in contacts else "not found"

def update(name, new_values):


if name in contacts:
contacts[name] = new_values
print("a contact has been updated successfuly")

La couche de présentation :

une fois les primitives sont définies, on définit les fonctions nécessaires au bon fonc-
tionnement de notre application, notamment les fonctions qui permettent l’affichage des
informations d’un contact. à savoir :

— une fonction print_info() qui affiche une information se forme d’une case d’une table
en mode texte ;
— une fonction print_one_contact() qui affiche un contact se forme d’une ligne d’une
table table en mode texte ;

— une fonction print_all_contact() qui affiche les contacts se forme d’une table en
mode texte ;
5.3 Les tableaux associatifs : dict 85

def print_value(value):
print(f"| {value:14}",end=’ ’)

def new_line():
return "+"+’-’*107+’+\n’

def print_headers():
headers = f"| {’First name’:14} | {’Last name’:14} |
headers += f" {’Birthday’:14} | {’birthplace’:14} |"
headers += f" {’Phone number’:14} | {’Adress email’:20} |\n"
print(new_line())
print(headers)
print(new_line())

def print_contact(name):
info = contacts[name]
print_value(name)
for value in info.values():
print_value(value)
print(’|’)

def print_all_contacts():
print_headers()
for contact in contacts:
print_contact(contact)
print(new_line())
print()

Interaction avec l’utilisateur :


une application de gestion des contacts doit permettre à l’utilisateur de saisir les
informations d’un contact lors d’insertion ou de mise à jour. Pour cela, nous allons créer
les fonctions suivantes :
— une fonction get_value() qui permet de demander à l’utilisateur une information
avant sa suppression, sa création ou avant sa mise à jour ;
— une fonction set_value() qui permet définir (fixer) la valeur d’une information avant
sa création ou sa modification
— la fonction create_contact() qui fait appel à la fonction get_value() pour pouvoir créer
les informations d’un contact. Une ces informations sont définies on les stockent
dans un dictionnaire values et on fait appel à la primitive add() pour ajouter ce
contact.
— la fonction update_contact_by_name() : le contact à modifier est donné par son nom
ou une partie de son nom (firstname) grâce à la primitive find(). Une fois la liste des
contacts à modifier est trouvée, on parcourt cette liste et on demande à l’utilisateur
les informations à modifier avant de modifier le contact. La primitive update() est
appelée pour réellement mettre à jour le contact.
86 Chapitre 5. Dict et Set

— item pour la fonction remove_contact_by_name() :


5.3 Les tableaux associatifs : dict 87

def get_value(attribute,n=14):
return input(f"\t\tSet a new value of {attribute:{n}}:> ")

def set_value(values,attribute, new_value):


if attribute in values:
values[attribute] = new_value

def create_contact():
values = {}
first_name = get_value("first_name")
values[’last_name’] = get_value("last_name")
values[’birthday ’] = get_value("birthday")
values[’birthplace’] = get_value("birthplace")
values[’phonenumber’] = get_value("phonenumber")
values[’email’] = get_value("email",n=20)
add(first_name,values)

def update_contact_by_name():
name = get_value("first name")
for contact in find(name):
print_contact(contact)
query=input("\tDo you want to modify this contact[Y|N]?:>")
if query.lower()==’y’:
values = contacts[contact]
for attribute, value in values.items():
response=input(f"\tUpdate {attribute}’value[y|n]?:>")
if response.lower()==’y’:
new_value = get_value(attribute)
set_value(values, attribute, new_value)
update(contact, values)

def find_contact_by_name():
name = input("get the first name:> ")
print_headers()
for contact in find(name):
print_contact(contact)
print()

def remove_contact_by_name():
name = input("get the first name:> ")
for contact in find(name):
print_contact(contact)
query = input("Do yo want to delete this contact[y,n]?:>")
if query.lower==’y’:
remove(contact)
88 Chapitre 5. Dict et Set

L’application en mode texte


nous créons, enfin, la fonction principale main() de l’application qui fait appel aux
fonctions précédente. Nous avons choisi de mettre ces fonctions dans un dictionnaire afin
de révoquer son exécution à partir de sa clé (un choix) saisie par l’utilisateur. L’avantage,
donc, est d’éviter trop de if dans l’appel des fonctions :

def main():
menu ="""
1 - add contact(s)
2 - find contact(s)
3 - remove contact(s)
4 - update contact(s)
5 - display contact(s)
6 - quit
"""
actions = {1:create_contact, 2:find_contact_by_name ,
3:remove_contact_by_name, 4:update_contact_by_name,
5:print_all_contacts , 6:exit
}
while True:
print(menu)
resp = int(input("Your choice:> "))
if resp in range(1,6):
function=actions.get(resp)
function()
elif resp == 6:
print ("bye")
break
else:
print("Error!!: get an integer fro 1 to 6")
continue

Voici la trace d’un test de la fonction main() pour montrer un déroulement de l’exécu-
tion :

1 - add contact(s)
2 - find contact(s)
3 - remove contact(s)
4 - update contact(s)
5 - display contact(s)
6 - quit

Your choice:> 1
Set a new value of first_name :> adoch
Set a new value of last_name :> mohammedo
Set a new value of birthday :> 2002-05-18
Set a new value of birthplace :> Rabta
5.3 Les tableaux associatifs : dict 89

Set a new value of phonenumber :> +212756895213


Set a new value of email :> med.adoch@xyz.com
a contact has been added successfuly

1 - add contact(s)
2 - find contact(s)
3 - remove contact(s)
4 - update contact(s)
5 - display contact(s)
6 - quit

Your choice:> 1
Set a new value of first_name :> Imami
Set a new value of last_name :> Nora
Set a new value of birthday :> 1998-12-25
Set a new value of birthplace :> Fès
Set a new value of phonenumber :> +212661587968
Set a new value of email :> n.imami@abc.net
a contact has been added successfuly

1 - add contact(s)
2 - find contact(s)
3 - remove contact(s)
4 - update contact(s)
5 - display contact(s)
6 - quit

Your choice:> 1
Set a new value of first_name :> Kadouri
Set a new value of last_name :> rachid
Set a new value of birthday :> 2000-12-13
Set a new value of birthplace :> Agadir
Set a new value of phonenumber :> +212569854732
Set a new value of email :> r.kadouri@site.org
a contact has been added successfuly

1 - add contact(s)
2 - find contact(s)
3 - remove contact(s)
4 - update contact(s)
5 - display contact(s)
6 - quit

Your choice:> 5
+-----------------------------------------------------------------------------------
90 Chapitre 5. Dict et Set

| First name | Last name | Birthday | birthplace | Phone number | Adress email

+-----------------------------------------------------------------------------------

| adoch | mohammedo | 2002-05-18 | Rabta | +212756895213 | med.adoch@xyz


+-----------------------------------------------------------------------------------

| Imami | Nora | 1998-12-25 | Fès | +212661587968 | n.imami@abc.n


+-----------------------------------------------------------------------------------
| Kadouri | rachid | 2000-12-13 | Agadir | +212569854732 | r.kadouri@sit
+-----------------------------------------------------------------------------------

1 - add contact(s)
2 - find contact(s)
3 - remove contact(s)
4 - update contact(s)
5 - display contact(s)
6 - quit

Your choice:> 4
Set a new value of first name :> adoc
| adoch | mohammedo | 2002-05-18 | Rabta | +212756895213 | med.adoch@xyz.
Do you want to modify this contact [Y|N]? :> y
Updating last_name’value,[Y|N]? :> y
Set a new value of last_name :> mohamed
Updating birthday ’value,[Y|N]? :> n
Updating birthplace’value,[Y|N]? :> y
Set a new value of birthplace :> Rabat
Updating phonenumber’value,[Y|N]? :> n
Updating email’value,[Y|N]? :> n
a contact has been updated successfuly

1 - add contact(s)
2 - find contact(s)
3 - remove contact(s)
4 - update contact(s)
5 - display contact(s)
6 - quit

Your choice:> 5
+-----------------------------------------------------------------------------------

| First name | Last name | Birthday | birthplace | Phone number | Adress email
5.3 Les tableaux associatifs : dict 91

+-----------------------------------------------------------------------------------

| adoch | mohamed | 2002-05-18 | Rabat | +212756895213 | med.adoch@xyz


+-----------------------------------------------------------------------------------

| Imami | Nora | 1998-12-25 | Fès | +212661587968 | n.imami@abc.n


+-----------------------------------------------------------------------------------

| Kadouri | rachid | 2000-12-13 | Agadir | +212569854732 | r.kadouri@sit


+-----------------------------------------------------------------------------------

1 - add contact(s)
2 - find contact(s)
3 - remove contact(s)
4 - update contact(s)
5 - display contact(s)
6 - quit

Your choice:> 3
get the first name:> Imam
| Imami | Nora | 1998-12-25 | Fès | +212661587968 | n.imami@abc.net
Do yo want to delete this contact[y,n]? :> y

1 - add contact(s)
2 - find contact(s)
3 - remove contact(s)
4 - update contact(s)
5 - display contact(s)
6 - quit

Your choice:> 8
Error!!: get an integer fro 1 to 6

1 - add contact(s)
2 - find contact(s)
3 - remove contact(s)
4 - update contact(s)
5 - display contact(s)
6 - quit

Your choice:> 6
bye
92 Chapitre 5. Dict et Set

5.4 Les ensembles : set


Les ensembles sont des structures de données similaires à des listes ou à des diction-
naires, mais qui ne peuvent contenir que des éléments uniques.

5.4.1 Définition et création


Définition
Un ensemble ou set est une collection itérable non ordonnées d’éléments hachables
unique.

On peut créer un ensemble via les accolades comme les dictionnaire mais sans clés :
un ensemble de valeurs uniqueq :
Création
>>> # première méthode
>>> set_1 = set([1, 2, 3, 4, 4, 4])
>>> set_1 # pas d’occurrence multiple
{1, 2, 3, 4}

>>> # deuxième méthode


>>> E = {’a’, ’b’, ’c’, ’d’}

>>> # Ajout d’un élément à un ensemble


>>> set_1.add(5)

>>> Suppression d’un élément dans un ensemble


>>> set_1.remove(1)

# Vérification de l’existence d’un élément dans un ensemble


print(3 in set_example)

5.4.2 Accès aux données et méthodes


Le type set ressemble à la notion de l’ensemble en mathématique. Pour tester l’apparte-
nance d’un élément, on utilise l’opérateur in :
Test d’appartenance
>>> E = {’a’, ’b’, ’c’, ’d’}

>>> ’c’ in E
True
>>> ’x’ in E
False

Les set sont itérables : on peut parcourir les éléments d’un set :
5.4 Les ensembles : set 93

Test d’appartenance
>>> for e in E:print(e)
’a’
’b’
’c’
’d’

On peut ajouter ou supprimer un élément au set grâce aux méthodes add, discard,
remove :

L’ajout et la suppression
>>> E.add(’x’)
>>> E
{’a’, ’b’, ’c’, ’d’, ’x’}

>>> # remove permet de supprimer un élément existant.


>>> E.remove(’x’)
>>> E
{’a’, ’b’, ’c’, ’d’}

>>> # Une Erreur est générée si cet élément n’existe pas


>>> E.remove(’x’)
KeyError: ’x’

>>> # discard permet de supprimer un élément existant.


>>> # Rien n’est plus générée si cet élément n’existe pas
>>> E.discard(’x’)
>>> E
{’a’, ’b’, ’c’, ’d’}

On peut faire les opérations ensembliste telles que l’union, l’intersection, la différence
et la différence symétrique
94 Chapitre 5. Dict et Set

Opérations ensemblistes
>>> A = {’a’, ’b’, ’c’, ’d’}
>>> B = {’g’, ’c’, ’d’, ’f’}

>>> # L’union par: union ou par: |


>>> A.union(B)
{’a’, ’b’, ’c’, ’d’, ’g’, ’f’}
>>> A | B
{’a’, ’b’, ’c’, ’d’, ’g’, ’f’}

>>> # L’intersection par intersection ou par : &


>>> A & (B)
{’c’, ’d’}
>>> A | B
{’a’, ’b’, ’c’, ’d’, ’g’, ’f’}

>>> # La différence par difference ou par : -


>>> A - B
{’a’, ’b’, ’g’, ’f’}

>>> # La différence symétrique par symetric_difference ou par : ^


>>> A ^ B
{’a’, ’b’, ’g’, ’f’}

5.5 Pile implémenté par un dictionnaire


vous pouvez implémenter une pile à l’aide d’un dictionnaire en Python. Une pile est
une structure de données qui respecte le principe "dernier entré, premier sorti" (LIFO), ce
qui signifie que l’élément le plus récemment ajouté est le premier à être retiré.
Les éléments d’un set sont ajoutés grâce à une fonction de hachage : la méthode pop
permet de renvoyer et supprimer un élément aléatoirement :
Méthode Pop
>>> A = {’a’, ’b’, ’c’, ’d’}
>>> A.pop()
’c’

Les set sont, comme les dict, non ordonnée c’est à dire que les éléments ne sont pas
ajoutés dans l’ordre de leurs apparitions. Dans l’exemple précédent, L’élément supprimé
est ’c’ et non plus le dernier élément ajouté ’d’
Vous pouvez implémenter une pile en utilisant un dictionnaire où les clés représentent
l’ordre d’ajout des éléments et les valeurs représentent les éléments eux-mêmes. Chaque
fois que vous ajoutez un élément à la pile, vous pouvez donner à sa clé un nouveau numéro
5.6 Conclusion 95

unique. Lorsque vous retirez un élément de la pile, vous pouvez retirer l’élément associé à
la clé la plus élevée.
Voici un exemple d’implémentation d’une pile à l’aide d’un dictionnaire en Python :

stack = {}
index = 0

def push(element):
global index
stack[index] = element
index += 1

def pop():
global index
if index == 0:
return None
index -= 1
element = stack[index]
del stack[index]
return element

Notez que cette implémentation utilise une variable globale index pour suivre l’ordre
d’ajout des éléments à la pile. Cela permet d’assigner une nouvelle clé unique à chaque
élément ajouté à la pile.
vous ne pouvez pas implémenter une pile en utilisant des ensembles (sets) en Python.
Les ensembles sont des structures de données non ordonnées qui ne conservent pas l’ordre
d’insertion des éléments. Par conséquent, ils ne peuvent pas être utilisés pour implémenter
une pile, qui nécessite de connaître l’ordre d’ajout des éléments.
Cependant, vous pouvez utiliser des ensembles pour stocker des éléments uniques et
effectuer des opérations telles que l’union, l’intersection et la différence sur les ensembles.
Les ensembles sont souvent utilisés pour supprimer les doublons dans des collections de
données ou pour effectuer des tests de présence rapides.

5.6 Conclusion
Les dictionnaires et les ensembles présentent plusieurs avantages par rapport à d’autres
structures de données en Python, tels que les liste :
— Temps d’accès rapide : les dictionnaires et les ensembles utilisent une structure de
données appelée table de hachage qui permet d’accéder rapidement à un élément en
fonction de sa clé ou de sa valeur.
— Stockage d’éléments uniques : les ensembles ne peuvent stocker que des éléments
uniques, ce qui peut être très utile lorsque vous avez besoin de vérifier l’existence
d’un élément sans duplicata.
— Modification facile : les dictionnaires peuvent être modifiés en ajoutant, en suppri-
mant ou en modifiant des paires clé-valeur, ce qui peut être très utile lorsque vous
avez besoin de stocker des informations qui peuvent changer au fil du temps.
96 Chapitre 5. Dict et Set

— Taille dynamique : les dictionnaires et les ensembles peuvent être agrandis ou réduits
en fonction des besoins, ce qui les rend plus flexibles que les listes qui ont une taille
fixe une fois définies.
— Utilisation pour des tâches spécifiques : les dictionnaires sont souvent utilisés pour
stocker des données structurées, tandis que les ensembles sont souvent utilisés pour
des tâches telles que la vérification de l’existence d’un élément ou la suppression
des duplicatas.

5.7 Exercices
Exercise 5.1 Implémenter en Python, les fonctions suivantes dont chaque fonction est
décrite par son entrée et sa sortie :
1. Grouper les éléments d’une liste en fonction d’une clé :
— Entrée : Une liste de tuples lst et une fonction de clé key_func ;
— Sortie : Un dictionnaire qui groupe les éléments de la liste en fonction de la
valeur renvoyée par key_func pour chaque élément.
2. Union de deux dictionnaires : :
— Entrée : Deux dictionnaires d1 et d2 ;
— Sortie : Un dictionnaire qui contient les clés et les valeurs de d1 et d2. Si
une clé existe dans les deux dictionnaires, la valeur du second dictionnaire
sera utilisée.
3. Supprimer les doublons d’une liste :
— Entrée : Une liste lst ;
— Sortie : Une liste sans doublons
4. Déterminer les clés manquantes d’un dictionnaire par rapport à un ensemble de
clés :
— Entrée : Un dictionnaire d et un ensemble keyst ;
— Sortie : Un ensemble des clés manquantes dans d par rapport à keys
5. Trouver les valeurs associées à une liste de clés dans un dictionnaire :
— Entrée : Un dictionnaire d et une liste de clés keys ;
— Sortie : Une liste des valeurs associées à keys dans le dictionnaire d

Exercise 5.2 — Fonctions de Hachage. Une fonction de hachage est une fonction
mathématique qui prend en entrée une donnée de taille quelconque (par exemple, une
chaîne de caractères ou un nombre) et la transforme en une valeur numérique de taille
fixe appelée "hash". La fonction de hachage est conçue pour être rapide à calculer, et
pour que deux entrées différentes ne donnent jamais le même hash.
Les fonctions de hachage sont utilisées dans de nombreux domaines, tels que
la sécurité informatique (par exemple, pour stocker des mots de passe sécurisés), la
compression de données (par exemple, pour trouver rapidement des doublons dans les
données) et les structures de données telles que les tables de hachage (où les entrées
sont stockées en fonction de leur hash).
5.7 Exercices 97

Une fonction f () de hachage est dite sans collision si f est injective :

∀x ̸= y ⇒ f (x) ̸= f (y)

Les fonctions de hachage sans collision sont utilisées pour assigner un code numé-
rique unique à chaque élément d’une structure de données, telle qu’un dictionnaire.
Voici ci-dessous quelques exemples de fonctions de hachage simples :
Exemples
— Fonction de hachage de somme : cette fonction de hachage consiste à
additionner les codes ASCII de chaque caractère d’une chaîne de caractères
pour obtenir un code de hachage unique. Par exemple, pour la chaîne
’hello’, la fonction de hachage serait 104 + 101 + 108 + 108 + 111 = 532.
— Fonction de hachage de multiplication : cette fonction de hachage consiste
à multiplier chaque code ASCII d’une chaîne de caractères par un nombre
primaire. Par exemple, pour la chaîne ’hello’, la fonction de hachage
pourrait être 104 * 101 * 108 * 108 * 111 = 7438790400.
— Fonction de hachage de rotation : cette fonction de hachage consiste à
effectuer une opération de rotation sur les codes ASCII des caractères
d’une chaîne de caractères. Par exemple, pour la chaîne ’hello’, la fonction
de hachage pourrait être (104 « 1) + (101 « 2) + (108 « 3) + (108 « 4) +
(111 « 5) = 2049369601.

Questions :
1. Un dictionnaire dict en python peut avoir une liste comme clé ? justifier votre
réponse ?
2. les fonctions ci-dessus sont elles sans collisions ?
3. Programmer en python ces fonctions de Hachage ?
4. Comment peut-on utiliser ces fonctions pour stocker les données dans une liste
de taille fixe n ∈ N∗
5. écrire une fonction python qui permet calculer de "hacher" les noms des élèves
d’une classe, les stockes (haches) dans une listes et retourne cette liste.
6. écrire une fonction python qui renvoie True si un élève (nom) est dans une classe
donnée et False sinon.

Exercise 5.3 — Dict et set en Python. 1. Écrivez une fonction qui prend un dic-
tionnaire comme entrée et renvoie un nouveau dictionnaire qui inverse les clés et
les valeurs.
2. Écrivez une fonction qui prend un dictionnaire et un ensemble comme entrée et
renvoie un nouveau dictionnaire qui contient uniquement les clés présentes dans
l’ensemble.
98 Chapitre 5. Dict et Set

3. Écrivez une fonction qui prend deux dictionnaires comme entrée et renvoie un
ensemble qui contient les clés qui sont présentes dans les deux dictionnaires.
4. Écrivez une fonction qui prend un dictionnaire comme entrée et renvoie une liste
triée des valeurs.
5. Écrivez une fonction qui prend un ensemble comme entrée et renvoie un diction-
naire qui mappe chaque élément de l’ensemble à son nombre d’occurrences dans
l’ensemble.

Exercise 5.4 — Matrice creuse.. Une matrice creuse(sparse en anglais) est une
matrice comportant majoritairement des coefficients nuls. Autrement dit, le pourcentage
des coefficients non nuls est faible. Une image binaire contenant les codes 0 et 1 (0 pour
la couleur dominante et 1 correspondant aux pixels informatifs) peut être considérée
comme matrice creuse.
Il est ridicule de mémoriser tous les m x n coefficients d’une matrice de deux
dimensions (n,m). Il suffit d’en mémoriser les coefficients non nuls.
Nous avons déjà vu qu’une matrice M = (ai j )(i<n),( j<m) peut être représentée par
une liste de listes. Par exemple, la matrice :
 
0 1 0 0
M = 4 0 0 7 
0 0 0 11

sera représentée par par la liste :

M = [[0, 1, 0, 0], [4, 0, 0, 7], [0, 0, 0, 11]]

.
Afin d’économiser beaucoup de mémoire, On représente une telle matrice par un
dictionnaire dont les couples (key, value) sont ((i, j), ai j ) où ai j est l’élément de la
matrice d’indice i et j. Ainsi M[1,3]=7 ou bien M[(1,3)]=7 est l’élément M[1][3] dans
la notation de liste.
1. Écrire une fonction qui parcourt une liste de listes, et qui en construit le diction-
naire correspondant, avec l’omission des valeurs égales à zéro.
2. Écrire la conversion inverse.

Exercise 5.5 — Polynômes. La représentation choisie en problème 2 (page ) pour


coder un polynôme P est coûteuse en terme de mémoire. Imaginez combien de zéros
sont nécessaires pour coder le polynôme P(x) = 1 − 2x + 3x10000 ! !.
Une autre représentation peut être accepter est de coder le polynôme par un diction-
naire dont les clés sont les degrés et les valeurs sont les coefficients associés à chaque
degré. Par exemple, le polynôme précédente peut s’écrit sous la forme :

P = {0 : 1, 1 : 2, 10000 : 3}
5.7 Exercices 99
Répondre aux questions du problème 2 mais dans le sens où les polynômes sont
codés par un dictionnaire { d : c} pour chaque coefficient c de P non nul associé au
degré d. ■

Exercise 5.6 — PILE et FILE. Coder les fonctions primitives des piles et des files en
utilisant un dictionnaire comme support de stockage. ■

Problem 5.1 — Statistiques. Un météorologiste souhaite améliorer l’efficacité du traite-


ment des données qu’il utilise (La température moyenne mensuelle de chaque pays). Son
objectif étant de réaliser des traitements statistiques, il décide d’utiliser les structures des
données du langage Python.
En imposant que tous les pays aient 12 températures mensuelles et qu’elles soient
classées dans le même ordre, le météorologiste utilise la liste mois permettant de fixer
l’ordre des températures ainsi que le nom de chaque mois, et le dictionnaire Température :

Température = {
"France":[6, 5, 8, 12, 15, 17, 21, 22, 18, 9, 8, 6],
"Maroc":[16, 12, 18, 32, 28, 35, 43, 45, 35, 26, 25, 16]
}
Mois = ["Janvier","Février", ... ,"Décembre"]

1. Donner l’instruction permettant d’afficher en France la température du mois de


février sous la forme "France février 05".
2. Écrire une fonction AfficheMois(), ayant pour paramètre le nom d’un mois, le dic-
tionnaire Température et la liste Mois, et qui affiche pour tous les pays la température
du mois comme précédemment.
3. Écrire une fonction AjoutPays() qui prend comme paramètre le dictionnaire Tem-
pératures (définies comme précédemment) et comme paramètre le nom d’un pays
ainsi que la liste des températures associées à ce pays et l’ajoute au dictionnaire
Température. Par exemple AjoutPays(température,"Bresil",[25,. . ..23]).
4. Écrire une fonction ModificationPaysMois() qui prend comme paramètre d’entrée le
nom du pays, le nom du mois, la valeur de la nouvelle température, la liste Mois et
comme paramètre d’entrée sortie Température. Cette fonction doit modifier la valeur
de la température du pays pour le mois indiqué.
Par exemple ModificationPaysMois("France","Janvier",08,Température,Mois) doit
modifier la valeur de la température en France au mois de Janvier (ici 08 remplaçant
la valeur 06).
5. Donner la fonction MoyennePays() qui pour un pays donné en paramètre d’entrée
donne la moyenne annuelle des températures. Le Dictionnaire des températures sera
un paramètre d’entrée.
6. Donner la fonction moyenneMois() qui pour un mois donné (par exemple Mars)
donne la moyenne des températures de tous les pays. Le Dictionnaire des tempéra-
tures et la liste des mois seront des paramètres d’entrée.
7. Donner la fonction MoyenneMax() qui donne le pays dont la moyenne annuelle des
températures est la plus élevée. Le Dictionnaire des températures sera un paramètre
d’entrée.
8. Donner la fonction stableTempérature() ayant pour paramètre le Dictionnaire des
100 Chapitre 5. Dict et Set

températures qui retourne dans quel mois la température moyenne de tous les pays
est la même(avec une tolérance d’un degré).
III
Les structures de données
arborescentes

6 Les Fichiers de textes . . . . . . . . . . . 103


6.1 Présentation
6.2 Définitions et vocabulaire
6.3 Manipulation de Fichiers textes
6.4 Exercices

7 calcul scientifique . . . . . . . . . . . . . . 111


7.1 Numpy, matplotlib et scipy

Bibliography . . . . . . . . . . . . . . . . . . . . . 127
Articles
Books
Misc

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
6. Les Fichiers de textes

6.1 Présentation
En programmation, la saisie et l’affichage de données sont très importants : c’est le
moyen de communication directe entre le programmeur et l’utilisateur final. Nous avons
utilisé jusqu’à maintenant la fonction de saisie input() et la fonction d’affichage sur écran
print(). Cependant, la saisie au clavier est fastidieux, notamment quand on doit répéter
l’exécution d’un programme avec les mêmes données. En outre, les données saisies ne
sont pas conservées à long terme car ses données sont chargées par le compilateur dans la
mémoire volatile de l’ordinateur.
La sauvegarde de données sur un support de stockage permanent est cruciale en
archivage et en science de manipulation de données : à titre d’exemple, sauvegarder
les traitement et les commandes des clients d’une entreprise et archivé l’historique des
opérations de différents clients.
Ce chapitre présente les fonctions et les méthodes qui permettent de manipuler les
données dans les objets fichier texte en Python.

6.2 Définitions et vocabulaire


6.2.1 Notion de fichier
Un fichier est une unité de stockage de données sur un support de stockage permanent
(disque dur, mémoire flash, etc, appelés mémoires de masse ou mémoires secondaires) et
on distingue deux types de fichiers :
1. Fichier binaire : une suite d’octets bien structurées selon un format (mp3, pdf, exe,
bin, png, jpg, ...)
2. Fichier texte : Une séquence de caractères (txt, csv, json, XML, ...)
104 Chapitre 6. Les Fichiers de textes

6.2.2 Notion de bloc


Un disque dur est découpés en un ensemble d’unités de stockage appelées : blocs de
taille fixe. La taille d’un bloc est précisé lors de l’opération de formatage du disque (512
O, 1024 O, etc).
Un fichier stocké sur un disque occupe un à plusieurs blocs de disque, autrement dit,
les données d’un fichiers sont réparties sur plusieurs blocs de la mémoire secondaire.

6.2.3 Notion de tampon mémoire


Puisque la manipulation des données se fait dans la mémoire centrale (RAM) de
l’ordinateur, il est donc nécessaire de faire transférer les données entre la mémoire vive et
la mémoire secondaire. La taille de données stockées dans un fichier est en général très
grande. Lorsqu’on ouvre un fichier, une petite partie de ses données est chargée en RAM
et les autres données sont chargées selon le besoin de l’utilisateur.
L’espace de mémoire centrale pour stocker un bloc de données est appelé un tam-
pon : Le contenu du tampon sera renouvelé avec les nouveaux blocs selon le besoin de
manipulation de données.

6.3 Manipulation de Fichiers textes


la manipulation d’un fichier texte[11] en python est l’ensemble d’opérations qui per-
mettent de l’ouvrir, l’ouvrir pour lire ou écrire les données toute en assurant le transfère de
données entre le tampon mémoire de l’objet fichier texte et ses blocs sur le disque. Donc,
pour manipuler un fichier il faut préciser les éléments suivants
— Le chemin (path) du fichier sur la mémoire secondaire (absolu ou relatif par rapport
au répertoire courant)
— La référence mémoire (variable) de l’objet en RAM qui pointe sur le fichier en
disque.
— Le mode d’ouverture : écriture, lecture ou les deux
— La position actuelle de l’écriture ou de la lecture : curseur

Remarque :
le curseur est un entier qui indique le nombre de caractères lus. Donc, il faut
distinguer le curseur (int) et l’objet graphique qui matérialise cet entier
(une barre verticale | qui clignote.

6.3.1 L’ouverture d’un fichier texte


La fonction open()[11] permet d’ouvrir un fichier et renvoie un objet fichier correspon-
dant. Ce dernier est une instance de la classe TexteIOWrapper qui est elle même une sous
classe de la classe TextIOBase. Le module io contient toute les classes et les constantes
nécessaire pour bien manipuler un fichier). La syntaxe générale est :

open(file, mode=’r’, buffering=-1, encoding=None, newline=None, closefd=True,


opener=None)

Les paramètres(Arguments) de la fonction open() sont :


6.3 Manipulation de Fichiers textes 105

1. file : le chemin absolu ou relatif au répertoire courant de fichier à ouvrir sur le disque.
Le chemin est donné sous forme d’une valeur de type str
2. mode : est un paramètre optionnel qui permet de spécifier le mode d’ouverture. Par
défaut, la valeur ’r’ permet d’ouvrir le fichier en mode lecture. Voici une liste des
autres modes disponible :
valeur description
’r’ Lecture (par défaut) et le curseur est placé au
début (0)
’w’ Écriture (avec remise à zéro : fichier est écrasé
si déjà existant) et le curseur est placé au début
’x’ Création exclusive (erreur si fichier déjà existant)
et le curseur est placé au début
’a’ Écriture (avec ajout à la fin) le curseur est placé
à la fin (EOF)
’b’ Mode binaire
’t’ Mode texte (par défaut)
’+’ ouvre en modification (lecture et écriture)
Le mode ’r’ est synonyme à ’rt’, c’est à dire un fichier texte ouvert en mode lecture
(read). On peut ouvrir un fichier binaire avec le mode ’b’ (’br’, ’bw’, ...). Cependant,
le programme officiel de classe prépas ne couvre que les fichiers textes (titre du
chapitre).
3. buffering : est un paramètre facultatif utilisé par défaut pour définir la politique
de mis en mémoire tampon. La taille de tampon est choisie par une heuristique
essayant de déterminer la taille des blocs du système sous-jacent en utilisant la
constante io.DEFAULT_BUFFER_SIZE. Sur de nombreux systèmes d’exploitations,
le tampon sera de 4096 ou 8192 octets.
4. Encoding : est le nom de l’encodage utilisé pour encoder ou décoder le fichier. Il doit
seulement être utilisé en mode texte. L’encodage par défaut dépend de la plateforme
(ce que locale.getpreferredencoding() donne), mais n’importe quel encodage de texte
pris en charge par Python peut être utilisé.
5. errors : une chaîne optionnel qui permet de spécifier comment les erreurs de l’en-
codage et de décodage sont gérées : la valeur ’strict’ permet de lever une exception
ValueError si une erreur de l’encodage est rencontré. (d’autre valeurs sont existent,
il suffit de voir la documentation officielle 1
6. newline : contrôle le mode retour à la ligne universel. Il peut être None, ”, ’\n’, ’\r’,
et ’\r\n’. Sur de nombreux système, ’\n’ est le séparateur de lignes par défaut.
7. closefd : : Quand on ouvre un fichier, celui-ci est attaché à un fichier système identifié
par un entier appelé descripteur de fichier (fd). L’ensemble des fichiers système
ouverts sont maintenu par le système dans une table appelé table de descripteur. On
peut, en python, spécifier le descripteur au lieu du chemin. Si closedfd=False alors
ce descripteur est gardé dans la table des descripteurs même si le fichier renvoyé est
fermé par le programmeur.
8. opener : paramètre facultatif qui renvoie un descripteur de fichier ouvert. Ceci est
important si on veut rediriger la sortie standard de print vers un fichier au lieu de
l’écran.
1. voir https ://docs.python.org/fr/3/library/functions.html#open
106 Chapitre 6. Les Fichiers de textes

D’une manière plus simple, pour ouvrir un fichier, il suffit de préciser deux choses : le
chemin et le mode. Le renvoi de open() est un objet fichier qu’il faut choisir son nom :

identificateur = open (path, mode)

L’exemple qui suit permet de créer un fichier ’data.csv’ dans le répertoire courant s’il
n’existe pas :

file = open (’data.csv’, ’w’)


...
file.close()

Notons bien que la méthode close() complète et termine les transferts des blocs de don-
nées vers les fichiers sur le support secondaire en cas d’écriture ou d’ajout ou modification
de données, et libère les zones de mémoires (tampons) associées aux fichiers. Cependant,
on peut ouvrir, traiter et fermer le fichier sans appeler la fonction close() avec la syntaxe
suivante :

with open (’data.csv’, ’w’) as file


...

Notons également que la clause with permet d’ouvrir simultanément plusieurs fichiers
selon la syntaxe suivante :

with open (...) as f1, open(...) as f2, ... :


...

Cependant, l’ouverture d’un fichier que ce soit en mode, r, w ou a) peut échouer[8],


par exemple, la mémoire est saturée, le disque est pleine ou une défaillance matérielle.,
donc, il faut rajouter les clauses qui permettent de gérer les exceptions :

try:
file=open(’data.csv’,’r’)
...
except Exception ex:
print("Erreur d’ouverture:")
print(ex)
file.close()

6.3.2 La lecture dans un fichier


Les fichiers textes en Python dispose d’un certain nombre de méthodes(fonctions) qui
permettent la lecture de données stockées dans un fichier. Nous présentons ici quelques
méthodes ordinaires :
6.3 Manipulation de Fichiers textes 107
la méthode read
Definition 6.3.1 read([n]) : permet de renvoyer une chaîne de n caractères et positionne
le curseur sur le caractère n. Si n n’est pas indiqué, elle lit tout le fichier et position le
curseur sur sa fin(EOF) :

f = open ( " n o t e . t x t " , ’ r ’ )


contenu = f . read ( )
p r i n t ( " Le t y p e de v a r i a b l e f e s t {} " . f o r m a t ( t y p e ( f ) ) )
p r i n t ( " Le t y p e de v a r i a b l e c o n t e n u e s t {} " . f o r m a t ( t y p e ( c o n t e n u ) ) )
p r i n t ( " La v a l e u r de c o n t e n u e s t : " )
p r i n t ( contenu )
f . close ()

Listing 6.1 – Méthode read

la méthode readline
Definition 6.3.2 readline() : permet de renvoyer une ligne de type "str"(le caractère ’\n’
est inclus) et positionne le curseur sur la ligne suivante. Le code suivant permet de lire
la première ligne :

f = open ( " n o t e . t x t " , ’ r ’ )


ligne = f . readline ()
p r i n t ( " Le t y p e de v a r i a b l e f e s t {} " . f o r m a t ( t y p e ( f ) ) )
p r i n t ( " Le t y p e de v a r i a b l e l i g n e e s t {} " . f o r m a t ( t y p e ( l i g n e ) ) )
p r i n t ( " La v a l e u r de l i g n e e s t : " )
print ( ligne )
f . close ()

Listing 6.2 – Méthode readline

la méthode readlines
Definition 6.3.3 readlines() : permet de renvoyer une liste contenant les lignes de fichier
et positionne le curseur en fin du fichier. Le code suivant permet d’afficher cette liste :

f = open ( " n o t e . t x t " , ’ r ’ )


lst = f . readlines ()
p r i n t ( " Le t y p e de v a r i a b l e f e s t {} " . f o r m a t ( t y p e ( f ) ) )
p r i n t ( " Le t y p e de v a r i a b l e l s t e s t {} " . f o r m a t ( t y p e ( l s t ) ) )
p r i n t ( " La v a l e u r de l s t e s t : " )
print ( lst )
f . close ()

Listing 6.3 – Méthode readlines

6.3.3 L’écriture dans un fichier


Pour écrire dans un fichier, Python dispose d’un certain nombre de méthodes(fonctions)
qui permettent de sauvegarder les données dans un fichier. Nous présentons ici quelques
méthodes ordinaires :
108 Chapitre 6. Les Fichiers de textes
la méthode write
Definition 6.3.4 write() :permet d’écrire une chaîne de caractères dans un fichier et
positionne le curseur en fin de celle-ci. Le code suivant permet d’insérer une ligne à la
fin du fichier "note.txt" :

f = open ( " n o t e . t x t " , ’ a ’ )


f . w r i t e ( " Nourmane , Asmae , 1 7 , 1 8 . 5 0 \ n " )
f . close ()

Listing 6.4 – Méthode write

R Pour ajouter une ligne et positionner le curseur sur la ligne suivante, il faut ajouter
explicitement le caractère "\n" en fin de cette ligne.

la méthode writelines
Definition 6.3.5 writelines() :permet d’écrire directement le contenu d’une liste. Nous
devons quand même insérer le caractère \n pour que le saut de ligne soit effectif dans le
fichier. Le code suivant permet d’insérer une liste de lignes à la fin du fichier "note.txt" :

f = open ( " n o t e . t x t " , ’ a ’ )


l s t = [ " Nourmane , Asmae , 1 7 , 1 8 . 5 0 \ n " , " Tourman , Anis , 1 3 . 2 5 , 8 . 5 0 \ n " ]
f . writelines ( lst )
f . close ()

Listing 6.5 – Méthode writelines

6.4 Exercices
Exercise 6.1 On dispose d’un fichier texte "notes.txt" dont lequel on a stocké les notes
d’une classe des étudiants selon le format suivant :
CNE, Nom, P r énom , DS1 , DS2 , DL , TD , TP
L1245786214 , Nourman , A l i , 1 2 , 8 , 1 4 , 1 2 , 13
L1011345215 , Tourman , Nora , 1 0 , 1 3 , 1 2 , 1 1 , 14
...

Développer une application python qui permet de lire ce fichier, calcule la moyenne
de chaque élève et stocke le résultat dans un autre fichier "result.txt" dont le format :
CNE, Nom P r énom , Moyenne , Appr é c i a t i o n
L1245786214 , Nourman A l i , 1 0 . 9 0 , Moyen
L1011345215 , Tourman , Nora , 1 2 . 0 5 , A s s e z B i e n
...

Problem 6.1 — Régression linéaire et Méthode des moindres carrés. la régression


recouvre plusieurs méthodes d’analyse statistique permettant d’approcher une variable à
partir d’autres qui lui sont corrélées. Un modèle de régression linéaire est un modèle de
6.4 Exercices 109

régression qui cherche à établir une relation linéaire entre une variable Y, dite expliquée, et
une ou plusieurs variables, dites explicatives X.
A titre d’exemple, si Y représente la tension artérielle et X est l’âge d’un individu, la
régression linéaire consiste à étudier la relation entre la variable Y et la variable X, c’est à
dire expliquer la tension à partir de l’âge d’un individu

Préparation de données
On utilisera un fichier texte pour stocker les données du modèle et on définira des
fonctions intermédiaire pour lire et écrire dans un fichier texte. Les données à traiter sont
numériques et il faut, donc, les nettoyer (convertir texte en float, supprimer les espaces et
les caractères d’échappement) afin de construire les listes X et Y.
1. Écrire un programme python permettant de créer le fichier ’courbe.txt’ contenant les
éléments suivants :
(a) 10 : nombre de points du fichier ;
(b) 25 ; 10.9 : abscisse et ordonnée du premier point
(c) 20 ; 9.3
(d) 15 ; 8.2
(e) 12 ; 7.5
(f) 9 ; 6.2
(g) 6 ; 5.8
(h) 3 ; 4.2
(i) 0 ; 3.9
(j) -3 ; 2.8
(k) -6 ; 2 : abscisse et ordonnée du dernier point
Les valeurs numériques sont données à titre d’exemple et il faut les lire à partir du
clavier. Notez bien que les xi et yi sont séparés par point virgules ( ;) et chaque ligne
contient uniquement un seul point xi ; yi sauf la première ligne qui indique le nombre
total des points
2. Écrire un programme Python permettant d’ouvrir le fichier en lecture, de le lire et
de construire la liste X des abscisses et la liste Y des ordonnées contenues dans ce
fichier. X et Y sont deux listes.
3. Écrire un programme Python permettant de représenter les points sur une figure.

Estimer le modèle par la méthode des moindres carrés


4. On cherche à modéliser les n points expérimentaux (x1 , y1 ), (x2 , y2 )..., (xn , yn ) par
une fonction polynôme du premier ordre, de la forme : y = ax + b. la méthode des
moindres carrés consiste à chercher les coefficients a et b pour que la somme des
carrés des erreurs soit minimale.
On admet que :
i=n i=n j=n
n ∑ xi yi − ( ∑ xi )( ∑ x j )
i=1 i=1 j=1
a= i=n i=n
n ∑ xi2 − ( ∑ xi )2
i=1 i=1

et
b = y − ax
110 Chapitre 6. Les Fichiers de textes
i=n i=n
1 1
où y = n ∑ yi est la moyenne des yi et x = n ∑ xi la moyenne des xi
i=1 i=1
5. Écrire un programme Python permettant de calculer les paramètres a et b correspon-
dant aux points expérimentaux de la question 2. La fonction prédéfinie sum est non
autorisé et il fallait écrire vos propres fonctions intermédiaire
6. Écrire un programme Python permettant de représenter graphiquement la fonction
ymod élisé = ax + b
On fournit les instructions Python pour la gestion des fichiers :
— f=open(’fichier.txt’, ’w’) : où fichier.txt désigne le nom du fichier. le mode d’ouver-
ture peut être ’w’ pour write, ’r’ pour read ou ’a’ pour append.
— f.readline() : lecture d’une ligne du fichier f
— ’\n’ : caractère d’échappement : saut de ligne
— c.strip() : renvoie une chaîne sans les espaces et les caractères d’échappement en
début et en fin de la chaîne c
— c.split(sep=’ ;’) renvoie une liste de mots qui sont séparés par ’ ;’
— f.write(’exemple’) : écrit dans le fichier f la chaîne de caractères ’exemple’
— f.close() : ferme le fichier f
7. calcul scientifique

Dans de ce chapitre, nous allons écrire les premières algorithmes numérique qui tra-
vaillent sur des nombres flottants et non plus sur les entiers. Les nombres réels de type float
comporte nombreuse approximations : conversion entre nombres décimaux et nombres
dyadiques, calculs approchés... avec pour conséquences les phénomènes d’arrondis, d’ab-
sorption et d’annulation .

7.1 Numpy, matplotlib et scipy


Nous allons présenter, dans cette première section, les bibliothèques Python : Numpy,
Scipy et matplotlib. Notre objectif est de présenter les différentes classes et fonctions
dédiées au calcul scientifique sous Python.
Nous vous invitons à étudier les différentes classes et fonctions proposées par ces
modules (étude de l’existant) et de programmer une version personnelle. Pour cela, penser
à utiliser le style de programmation fonctionnelle et le style orienté objet que nous avons
étudié en première année.

7.1.1 calcul vectoriel et matriciel avec numpy


NumPy est une bibliothèque sous Python, destinée à manipuler des matrices ou tableaux
multidimensionnels ainsi que des fonctions mathématiques opérant sur ces tableaux.
Les tableaux numpy sont sous-jacents à de nombreux packages dédiés au calcul scienti-
fique sous Python. Le manuel de référence : http ://docs.scipy.org/doc/numpy/reference/index.html
Pour commencer, il faut importer Numpy au début du programme et ensuite on peut
utiliser les fonctions qu’y sont prédéfinies. Par exemple, on définit des tableaux et on fait
des opérations arithmétiques avec les valeurs qu’ils contiennent.
Attention, les tableaux « numpy » ne gèrent que les objets de même type

Vecteurs
112 Chapitre 7. calcul scientifique

>>> i m p o r t numpy a s np # p a r l a s u i t e on u t i l i s e r a l ’ a l i a s np p o u r numpy


>>>v=np . a r r a y ( [ 1 , 1 2 , 3 , 1 8 ] )
>>>v
a r r a y ( [ 1 , 12 , 3 , 1 8 ] )
>>> t y p e ( v )
< c l a s s ’ numpy . n d a r r a y ’ >
>>>v . s i z e ( )
4
>>> v . s h a p e
(4 ,)

Listing 7.1 – définition d’un vecteur en numpy

On peut facilement définir des arrays contenants des séquences de valeurs numériques
avec la fonction arange() :
>>> # 1 p a r a m e t r e : donne l a l o n g u e u r de l a s e q u e n c e ( en p a r t a n t de z e r o )
>>> v=np . a r a n g e ( 3 )
>>> v
[0 ,1 , 2]
>>> # 2 p a r a m e t r e s : d e b u t e t f i n de l a s e q u e n c e
>>> # ( a t t e n t i o n , l e s i n d i c e s commencent a z e r o , l a d e r n i e r e v a l e u r e s t
donc e x c l u e )
>>> v=np . a r a n g e ( 3 , 9 )
array ([3 , 4 , 5 , 6 , 7 , 8])
>>> # 3 p a r a m e t r e s : d é b u t , f i n de l a s e q u e n c e e t i n c r e m e n t ( i c i l e p a s
e s t de deux )
>>> v=np . a r a n g e ( 3 , 9 , 2 )
>>> v
array ([3 , 5 , 7])
>>> # é g a l e m e n t a v e c d e s v a l e u r s non e n t i è r e s
>>> v = np . a r a n g e ( 0 , 3 2 , np . p i )
>>> v
array ([ 0. , 3.14159265 , 6.28318531 , 9.42477796 ,
12.56637061 , 15.70796327 , 18.84955592 , 21.99114858 ,
25.13274123 , 28.27433388 , 31.41592654])

Listing 7.2 – méthode arrange de numpy

La fonction linspace() permet d’obtenir un array allant d’unevaleur de départ à une


valeur de fin avec un nombre donné d’éléments (elle sera utilisé dans la section suivante
sur Matplotlib).
>>> l i s t e de 3 a 9 a v e c 10 é l é m e n t s é q u i d i s t a n t s
>>> np . l i n s p a c e ( 3 , 9 , 1 0 )
array ([ 3. , 3.66666667 , 4.33333333 , 5. ,
5.66666667 ,
6.33333333 , 7. , 7.66666667 , 8.33333333 , 9.
])

Listing 7.3 – subdivision avec linspace

Rajouter/supprimer une valeur dans un array :


7.1 Numpy, matplotlib et scipy 113

>>> a=np . a r r a y ( [ 1 . 2 , 2 . 5 , 3 . 2 , 1 . 8 ] )
>>> a= a p p e n d ( a , 1 0 )
>>> a
array ([ 1.2 , 2.5 , 3.2 , 1.8 , 10. ])
>>> # c o n c a t é n a t i o n 2 v e c t e u r s
>>> x=np . a r r a y ( [ 1 , 2 , 5 , 6 ] )
>>> y=np . a r r a y ( [ 2 , 1 , 7 , 4 ] )
>>> z=np . a p p e n d ( x , y )
array ([1 , 2 , 5 , 6 , 2 , 1 , 7 , 4])
>>> # s u p p r e s s i o n v i a i n d i c e
>>> b=np . d e l e t e ( a , 2 )
array ([ 1.2 , 2.5 , 1.8 , 10. ])

Listing 7.4 – modification d’un objet array


Accès aux valeurs par indice :
>>> v=np . a r r a y ( [ 1 . 2 , 7 . 4 , 4 . 2 , 8 . 5 , 6 . 3 ] )
>>> v [ 0 ] # l e 1 e r i n d i c e e s t 0 ( z é r o ) }
1.2
>>> v [ v . s i z e − 1 ] # d e r n i è r e v a l e u r
6.3
>>> # v . s i z e e s t ok p a r c e que v e s t un v e c t e u r ou a u s s i
>>> v [ − 1 ]
6.3
>>> # du d é b u t à l ’ i n d i c e 3 ( non i n c l u s ) }
>>> v [ : 3 ]
array ([1.2 , 7.4 , 4.2])
>>> # p l a g e d ’ i n d i c e s c o n t i g u s
>>> v [ 1 : 5 ]
array ([7.4 , 4.2 , 8.5 , 6.3])
>>> # i n d i c e 1 à 5 a v e c un p a s de 2
>>> v [ 1 : 5 : 2 ]
array ([7.4 , 8.5])

Listing 7.5 – accès aux valeurs


Tri et recherche :
>>>v=np . a r r a y ( [ 1 . 2 , 7 . 4 , 4 . 2 , 8 . 5 , 6 . 3 ] )
>>> # r e c h e r c h e v a l e u r max
>>> np . max ( v )
8.5
>>> # r e c h e r c h e v a l e u r min
>>> np . min ( v )
1.2
>>> # r e c h e r c h e i n d i c e de v a l e u r max
>>> np . argmax ( v )
3
>>> # somme d e s v a l e u r s
>>> np . sum ( v )
27
>>> # t r i d e s v a l e u r s
>>> np . s o r t ( v )
array ([1.2 , 4.2 , 6.3 , 7.4 , 8.5])
>>> v
114 Chapitre 7. calcul scientifique

array ([1.2 , 7.4 , 4.2 , 8.5 , 6.3])


>>> # v a l e u r s d i s t i n c t e s
>>> a = np . np . a r r a y ( [ 1 , 2 , 2 , 1 , 1 , 2 ] )
>>> np . u n i q u e ( a )
array ([1 , 2])
>>> a
array ([1 , 2 , 2 , 1 , 1 , 2])

Listing 7.6 – quelques fonctions numpy


Les opérations arithmétique qui opèrent élément par élément :
>>> # d é f i n i r un p r e m i e r v e c t e u r
>>> a = np . a r a n g e ( 1 , 4 )
>>> # d é f i n i r un s e c o n d v e c t e u r
>>> b= np . a r a n g e ( 1 : 4 )
>>> c = a+b # a d d i t i o n
>>> c
[2 4 6]
>>> a * b # m u l t i p l i c a t i o n }
[1 4 9]
>>> b=np . a r r a y ( [ 2 . 5 , 2 . 5 , 2 . 5 ] )
>>> a −b # s o u s t r a c t i o n
a r r a y ( [ − 1 . 5 −0.5 0 . 5 ] )
>>> a=np . a r r a y ( [ 2 , 8 , 3 ] )
>>> b=np . a r r a y ( [ 1 , 2 , 3 ] )
>>> a / b # d i v i s i o n
array ([2. , 4. , 1.])

Listing 7.7 – opérations élément par élément


La multiplication d’un vecteur par un scalaire :
>>> a=np . a r r a y ( [ 1 , 2 , 3 ] )
>>> s = 0 . 5 # d é f i n i r un s c a l a i r e
>>> c= s * a # m u l t i p l i c a t i o n v e c t e u r p a r un s c a l a i r e
>>> c
array ([0.5 , 1. , 1.5])

Listing 7.8 – Multiplication vecteur-scalaire


Produit scalaire
>>> a=np . a r r a y ( [ 1 , 2 , 3 ] )
>>> b=np . a r r a y ( [ 1 , 2 , 3 ]
>>> a . d o t ( b ) # p r o d u i t s c a l a i r e
14

Matrices
Une matrice est un tableau (array) à 2 dimensions (tableau de tableaux).
>>> # c r e a t i o n d ’ une m a t r i c e }
>>> A = np . a r r a y ( [ [ 1 , 2 , 3 ] , [ 4 , 5 , 6 ] ] )
>>> A
array ([[1 , 2 , 3] ,
7.1 Numpy, matplotlib et scipy 115

[4 , 5 , 6]])
>>>> A, d t y p e # t y p e d e s é l é m e n t s de l a m a t r i c e
dtype ( ’ int64 ’ )
>>> A . s h a p e # r e n v o i e un t u p l e ( num . l i g n e s , num . c o l o n n e s )
(2 , 3)
>>> A . s i z e # nombre t o t a l e de v a l e u r s
6
>>> B= np . a r r a y ( [ [ 1 . 2 , 2 . 5 ] , [ 3 . 2 , 1 . 8 ] ] )
array ([[1.2 , 2.5] ,
[3.2 , 1.8]])
>>> t y p e ( B )
< c l a s s ’ numpy . n d a r r a y ’ >
>>> B . d t y p e
dtype ( ’ f l o a t 6 4 ’ )
>>> B . s h a p e
(2 , 2)
>>> # m a t r i c e s de v a l e u r s i d e n t i q u e s , p a r ex . p o u r une i n i t i a l i s a t i o n
>>> C=np . z e r o s ( ( 2 , 1 ) ) # a t t e n t i o n , d o u b l e p a r e n t è s e
>>> C
array ( [ [ 0 . ] ,
[0.]])
>>> p r i n t ( "A= " , A)
A= [ [ 1 2 3 ]
[4 5 6 ]]
>>> # p l u s g é n é r a l e m e n t
>>> C = np . f u l l ( ( 2 , 4 ) , f i l l _ v a l u e = 0 . 3 )
array ([[0.3 , 0.3 , 0.3 , 0.3] ,
[0.3 , 0.3 , 0.3 , 0.3]])
>>> # c r é a t i o n d ’ une m a t r i c e 3 x3 de v a l e u r s a l é a t o i r s d ’ une
d i s t r i b u t i o n uniforme sur [0 , 1]
>>> D=np . random . r a n d ( 3 , 3 )
>>> D
array ([[0.59597357 , 0.78596938 , 0.02071907] ,
[0.75553271 , 0.02298006 , 0.71780333] ,
[0.13262969 , 0.77058417 , 0.81046751]])
>>> # c r é a t i o n d ’ une m a t r i c e 2 x4 d ’ e n t i e r s a l é a t o i r e s e n t r e 0 e t 5
exclu .
>>> E=np . random . r a n d i n t ( 5 , s i z e = ( 2 , 4 ) )
array ([[4 , 4 , 0 , 3] ,
[2 , 1 , 0 , 1]])

Listing 7.9 – création de matrices

On peut redimensionner une matrice par ajout d’une ligne ou d’une colonne
>>> # m a t r i c e de v a l e u r s
>>> A = np . a r r a y ( [ [ 1 . 2 , 2 . 5 ] , [ 3 . 2 , 1 . 8 ] , [ 1 . 1 , 4 . 3 ] ] )
>>> A
array ([[1.2 , 2.5] ,
[3.2 , 1.8] ,
[1.1 , 4.3]])
>>> # a j o u t e r une l i g n e : A c c o l e r l e v e c t e u r b en t a n t que n o u v e l l e
l i g n e ( a x i s = 0 ) de l a m a t r i c e A
>>> b = np . a r r a y ( [ [ 4 . 1 , 2 . 6 ] ] )
>>> b
array ([[4.1 , 2.6]])
116 Chapitre 7. calcul scientifique

>>> C = np . a p p e n d (A, b , a x i s = 0 )
>>> C
array ([[1.2 , 2.5] ,
[3.2 , 1.8] ,
[1.1 , 4.3] ,
[4.1 , 2.6]])
>>> # a j o u t e r une c o l o n n e : A c c o l e r l e v e c t e u r d en t a n t que n o u v e l l e
c o l o n n e ( a x i s = 1 ) de l a m a t r i c e A
>>> d = np . a r r a y ( [ [ 7 . 8 ] , [ 6 . 1 ] , [ 5 . 4 ] ] )
>>> D = np . a p p e n d (A, d , a x i s = 1 )
>>> D
array ([[1.2 , 2.5 , 7.8] ,
[3.2 , 1.8 , 6.1] ,
[1.1 , 4.3 , 5.4]])
# i n s e r t i o n : I n s e r t i o n de b en t a n t que n o u v e l l e l i g n e ( a x i s = 0 ) à l a
p o s i t i o n numé r o 1
>>> E=np . i n s e r t (A, 1 , b , a x i s = 0 )
>>> E
array ([[1.2 , 2.5] ,
[4.1 , 2.6] ,
[3.2 , 1.8] ,
[1.1 , 4.3]])
# suppression
>>> F=np . d e l e t e (A, 1 , a x i s = 0 )
>>> F
array ([[1.2 , 2.5] ,
[1.1 , 4.3]])
# m o d i f i e r l a d i m e n s i o n d ’ une m a t r i c e e x i s t a n t e p a r c o u r t l e s donn é e s
l i g n e s par ligne
>>> G=np . r e s i z e (A, ( 2 , 3 ) )
>>> G
array ([[1.2 , 2.5 , 3.2] ,
[1.8 , 1.1 , 4.3]])

Listing 7.10 – redimensionnement d’une matrice


Opérations avec les matrices :
>>> # d é f i n i r une p r e m i è r e m a t r i c e
>>> A = np . a r r a y ( [ [ 1 , 2 , 3 ] , [ 4 , 5 , 6 ] ] )
>>> # d é f i n i r une d e u x i ème m a t r i c e
>>> B = np . a r r a y ( [ [ 1 , 2 , 3 ] , [ 4 , 5 , 6 ] ] )
>>> A+B # a d d i t i o n
array ( [ [ 2 , 4 , 6] ,
[ 8 , 10 , 1 2 ] ] )
>>> A / B # d i v i s i o n
array ([[1. , 1. , 1.] ,
[1. , 1. , 1. ]] )
>>> A−B # s o u s t r a c t i o n
array ([[0 , 0 , 0] ,
[0 , 0 , 0]])

Listing 7.11 – calcul matriciel


Multiplication (produit matriciel) :
7.1 Numpy, matplotlib et scipy 117

>>> A = np . a r r a y ( [ [ 1 , 2 ] , [ 3 , 4 ] , [ 5 , 6 ] ] )
>>> B = np . a r r a y ( [ [ 1 , 2 ] , [ 3 , 4 ] ] )
>>> A
array ([[1 , 2] ,
[3 , 4] ,
[5 , 6]])
>>> B
array ([[1 , 2] ,
[3 , 4]])
>>> A . d o t ( B ) # m u l t i p l i c a t i o n m a t r i c i e l l e
array ( [ [ 7 , 10] ,
[15 , 22] ,
[23 , 34]])
>>> A @ B # idem : m u l t i p l i c a t i o n m a t r i c i e l l e a v e c @
array ( [ [ 7 , 10] ,
[15 , 22] ,
[23 , 34]])

Listing 7.12 – produit matriciel


Multiplication matrice-vecteur :
>>> # d é f i n i r une m a t r i c e
>>> A = np . a r r a y ( [ [ 1 , 2 ] , [ 3 , 4 ] , [ 5 , 6 ] ] )
>>> # d é f i n i r un v e c t e u r
>>> B=np . a r r a y ( [ 0 . 5 , 0 . 5 ] )
>>> C = A . d o t ( B ) # m u l t i p l i c a t i o n v e c t e u r p a r m a t r i c e
>>> C
array ([1.5 , 3.5 , 5.5])

Listing 7.13 – produit matrice-vecteur


Multiplication matrice-scalaire :
>>> A = np . a r r a y ( [ [ 1 , 2 ] , [ 3 , 4 ] , [ 5 , 6 ] ] )
>>> # d é f i n i r un s c a l a i r e
>>> b = 0 . 5
>>> # m u l t i p l i c a t i o n m a t r i c e p a r un s c a l a i r e
>>> C = A* b
>>> C
array ([[0.5 , 1. ] ,
[1.5 , 2. ] ,
[2.5 , 3. ] ] )

Listing 7.14 – produit matrice-scalaire


Il existe plusieurs types de matrices avec des propriétés particulières (carrées, symétriques,
triangulaires,...).
— Matrice symétrique
# c r é a t i o n d ’ une m a t r i c e a l é a t o i r e
>>> A = np . random . r a n d ( 3 , 3 )
>>> A
array ([[0.02160253 , 0.87737048 , 0.32229603] ,
[0.25827898 , 0.96638833 , 0.62558965] ,
118 Chapitre 7. calcul scientifique

[0.95565121 , 0.79584441 , 0.80656096]])


>>> # c r é a t i o n d ’ une m a t r i c e A sym é t r i q u e ( en m u l t i p l i a n t A p a r s a
transpos ée )
>>> A = A . d o t (A . T )
>>> A
array ([[0.87412036 , 1.05508514 , 0.97884628] ,
[1.05508514 , 1.39197684 , 1.52049555] ,
[0.97884628 , 1.52049555 , 2.19717814]])

— Matrice triangulaire
>>> # d é f i n i r une m a t r i c e c a r r é e
>>> M = np . a r r a y ( [ [ 1 , 2 , 3 ] , [ 1 , 2 , 3 ] , [ 1 , 2 , 3 ] ] )
>>> l o w e r =np . t r i l (M) # m a t r i c e t r i a n g u l a i r e i n f é r i e u r e
>>> l o w e r
array ([[1 , 0 , 0] ,
[1 , 2 , 0] ,
[1 , 2 , 3]])
>>> u p p e r =np . t r i u (M) # m a t r i c e t r i a n g u l a i r e s u p é r i e u r
>>> u p p e r
array ([[1 , 2 , 3] ,
[0 , 2 , 3] ,
[0 , 0 , 3]])

— Matrice diagonale
>>> # d é f i n i r une m a t r i c e c a r r é e
>>> M = np . a r r a y ( [ [ 1 , 2 , 3 ] , [ 1 , 2 , 3 ] , [ 1 , 2 , 3 ] ] )
>>> d = np . d i a g (M) # e x t r a i r e l a d i a g o n a l e
>>> d
array ([1 , 2 , 3])
>>> M
array ([[1 , 2 , 3] ,
[1 , 2 , 3] ,
[1 , 2 , 3]])

>>> d
array ([1 , 2 , 3])
>>> M
array ([[1 , 2 , 3] ,
[1 , 2 , 3] ,
[1 , 2 , 3]])
>>> # c r é e r une m a t r i c e d i a g o n a l e à p a r t i r du v e c t e u r
>>> D=np . d i a g ( d )
>>> D
array ([[1 , 0 , 0] ,
[0 , 2 , 0] ,
[0 , 0 , 3]])

— Matrice identité
>>> I 3 =np . i d e n t i t y ( 3 )
>>> I 3
array ([[1. , 0. , 0.] ,
[0. , 1. , 0.] ,
7.1 Numpy, matplotlib et scipy 119

[0. , 0. , 1. ]] )

Opérations sur des matrices


>>> # c a l c u l e r l a m a t r i c e t r a n s p o s é }
M
array ([[1 , 2 , 3] ,
[1 , 2 , 3] ,
[1 , 2 , 3]])
>>> M. T
array ([[1 , 1 , 1] ,
[2 , 2 , 2] ,
[3 , 3 , 3]])
>>> np . t r a c e (M) # c a l c u l e r l a t r a c e
6

On utilise le sous-module linalg contenu dans Numpy pour les calculs d’algèbre linéaire.
>>> A=np . a r r a y ( [ [ 1 , 2 ] , [ 3 , 4 ] ] , d t y p e = f l o a t )
>>> A
array ([[1. , 2.] ,
[3. , 4.]])
>>> B=np . l i n a l g . i n v (A) # i n v e r s e de A
>>> B
array ([[ −2. , 1. ] ,
[ 1.5 , −0.5]])

>>> # c a l c u l e r l e d e t e r m i n a n t }
>>> d=np . l i n a l g . d e t (A)
>>> d
−2 .00 000 000 000 000 04

Listing 7.15 – inverse et déterminant d’une matrice

Résolution d’équations linéaires de type A.x = b, où A est une matrice, b et x deux vecteurs.
>>> # r é s o l u t i o n d ’ é q u a t i o n
>>> A=np . a r r a y ( [ [ 1 , 2 ] , [ 3 , 4 ] ] , d t y p e = f l o a t )
>>> b=np . a r r a y ( [ 1 . 7 , 1 . 0 ] )
>>> x =np . l i n a l g . s o l v e (A, b )
>>> x
array ([ −2.4 , 2.05])

Listing 7.16 – résolution d’un système d’équations

Parcours d’une matrice : double boucle sur les indices


>>> f o r i i n r a n g e ( 0 , A . s h a p e [ 0 ] ) :
f o r j in range (0 , A. shape [ 1 ] ) :
p r i n t (A[ i , j ] )

1.0
2.0
3.0
120 Chapitre 7. calcul scientifique

4.0
>>> # somme d e s v a l e u r s d ’ une m a t r i c e
>>> s = 0
>>> f o r i i n r a n g e ( 0 , A . s h a p e [ 0 ] ) :
f o r j in range (0 , A. shape [ 1 ] ) :
s +=A[ i , j ]

>>> s
10.0
>>> np . sum (A)
10.0

Listing 7.17 – parcourir une matrice

7.1.2 Visualisation avec Matplotlib


Matplotlib est une librairie graphique pour générer des figures scientifiques en 2D et
3D. Parmi les avantages de cette librairie, on peut citer :
— prise en main facile,
— des figures de haute qualité et plusieurs formats PNG, PDF, SVG, EPS, and PGF,
— le texte peut être formaté en
Tout d’abord, il faut importer le module matplotlib pour pouvoir utiliser dans votre
programme.
import m a t p l o t l i b . pylab as p l t

D’une manière générale les fonctions plt.plot attendent des vecteurs/matrices, c’est à dire
des tableaux de points du plan. On commence par afficher la fonction sinus.
import m a t p l o t l i b . pylab as p l t
i m p o r t numpy a s np
x=np . l i n s p a c e ( − 5 , 5 , 1 0 0 )
p l t . p l o t ( x , np . s i n ( x ) ) # on u t i l i s e l a f o n c t i o n s i n u s de Numpy
p l t . x l a b e l ( " axe des a b c i s s e s " )
plt . ylabel ( " fonction sinus " )
p l t . show ( )
7.1 Numpy, matplotlib et scipy 121

** Graphique "Scatter plot" (nuage de points)** Commençons par créer des points à
afficher.
# c r é a t i o n en a b s c i s s e d ’ un e n s e m b l e de p o i n t s s u r l \ PYZsq {} i n t e r v a l l e
[1 ,25]
xs = range ( 1 , 25)
# en o r d o n n é , p o u r c h a q u e p o i n t x d a n s l ’ e n s e m b l e xs , on c a l c u l e l a
valeur 1/ x
ys = [ 1 / x f o r x i n xs ]

Pour dessiner un "scatter plot" (nuage de point), on utilise la méthode scatter.


p l t . s c a t t e r ( xs , y s )
p l t . show ( )

On peut combiner ce graphique avec un deuxième nuage de points. Créons d’autres points.
# # c e t t e f o i s p o u r c h a q u e p o i n t x d a n s xs , j ’ a f f i c h e l a v a l e u r 1 / ( 2 5 − x )
>>> z s = [ 1 / ( 2 5 − x ) f o r x i n x s ]

Afficher les deux ensembles de points dans un même graphique.


>>> p l t . s c a t t e r ( xs , y s )
>>> p l t . s c a t t e r ( xs , z s )
>>> p l t . show ( ) }

Pour ajouter une légende, des axes et un titre à notre graphique (qui peuvent inclure du
code :
122 Chapitre 7. calcul scientifique

import m a t p l o t l i b . pylab as p l t

xs = range ( 1 , 2 5 )
ys = [ 1 / x f o r x i n xs ]
zs = [1/(25 − x ) f o r x i n xs ]
p l t . s c a t t e r ( xs , ys , l a b e l = " y = 1 / x " )
p l t . s c a t t e r ( xs , zs , l a b e l = " y = 1 / ( 2 5 − x ) " )
x \ PYZcb { } } \ PY{ l + s + s 2 } { \ PYZdl { } } \ PY{ l + s + s 2 } { \ PYZdq { } } \ PY{ p } { ) }
plt . xlabel ( "x"
p l t . y l a b e l ( " Valeur " )
p l t . t i t l e ( "Mon p r e m i e r s c a t t e r p l o t "
p l t . legend ( )
p l t . show ( )

Il est possible d’enregistrer la figure dans un fichier.


p l t . s a v f i g ( " mongraphe . png " )
# f o r m a t png p a r d é f a u t ou b i e n
p l t . s a v e f i g ( " mongraphe . p d f " , f o r m a t = " p d f " )

Un système de sous-figures plt.subplot() permet de juxtaposer différents graphiques

def f ( t ) :
r e t u r n np . exp ( t ) * np . c o s ( 2 * np . p i * t )

# d é f i n i t i o n d e s v e c t e u r s de p o i n t s
t 1 = np . a r a n g e ( 0 . 0 , 5 . 0 , 0 . 1 )
t 2 = np . a r a n g e ( 0 . 0 , 5 . 0 , 0 . 0 2 )
plt . figure (1)
p l t . subplot (221)
p l t . p l o t ( t 1 , f ( t 1 ) , " bo " , t 2 , f ( t 2 ) , " k " )
# bo = r o n d s b l e u e t k = c o u l e u r n o i r
p l t . subplot (222)
p l t . p l o t ( t 2 , np . c o s ( 2 * np . p i * t 2 ) , " r −− " )
# r −− = p e t i s t r a i t s r o u g e s

p l t . subplot (223)
p l t . p l o t ( t 2 , np . s i n ( 2 * np . p i * t 2 ) , " b− " )
# b− = t r a i t c o n t i n u b l e u
7.1 Numpy, matplotlib et scipy 123

7.1.3 Scipy :librairie d’algorithmes scientifiques


SciPy est un projet visant à unifier et fédérer un ensemble de bibliothèques Python à
usage scientifique. Scipy utilise les tableaux et matrices du module NumPy.
Les algorithmes et les fonctions de Scipy couvrent :

Fonctions spéciales (scipy.special)


Intégration (scipy.integrate)
Optimization (scipy.optimize)
Interpolation (scipy.interpolate)
Transformées de Fourier (scipy.fftpack)
Traitement du signal (scipy.signal)
Algèbre linéaire (scipy.linalg)
Statistiques (scipy.stats)

Chacun des ces sous-modules fournit un ensemble de fonctions et de classes qui


peuvent être utilisées pour résoudre des problèmes variés en lien avec le calcul scientifique.
Importer le module Scipy pour accéder à la libraire :
from s c i p y i m p o r t *
# * t o u t l e s modules

Au cas où un seul sous-module sera utilisé, il est possible de l’importer comme suit :
import scipy . l i n a l g
# i m p o r t e r l e s o u s module a l g è b r e l i n é a i r e

Intégration On s’intéresse maintenant au calcul numérique d’une intégrale du type :


Z b
f (x)dx.
a

Plusieurs méthodes fournissant une valeur approchée d’une intégrale sont implémentées
dans Scipy.
Par exemple romberg calcule une valeur approchée de l’intégral à l’aide de la méthode
de Romberg, trapz calcule une valeur approchée de l’intégral à l’aide de la méthode des
trapèzes, simps calcule une intégrale à l’aide de la méthode de Simpson.
124 Chapitre 7. calcul scientifique

Dans nos exemples on utilisera quad, (dblquad and tplquad) qui permettent de
calculer des intégrales simples, (doubles ou triples respectivement) avec une méthode non
spécifiée, optimisée par Python.
Une façon de calculer une intégrale avec Scipy, est donc de définir une fonction et puis
lui appliquer la méthode quad.
from s c i p y i m p o r t e i n t e g r a t e
>>># d é f i n i r une f o n c t i o n s i m p l e à i n t é g r e r
>>> d e f f ( x ) :
return x
>>> x _ l o w e r }=0 # b o r n e i n f é r i e u r e de l ’ i n t é g r a l e
>>> x _ u p p e r =1 # b o r n e s u p é r i e u r e de l ’ i n t é g r a l e
>>> v a l , a b s e r r = i n t e g r a t e . quad ( f , x _ l o w e r , x _ u p p e r )
>>> p r i n t " é v a l e u r de l ’ i n t é g r a l e = " , v a l , " e r r e u r en v a l e u r a b s o l u e = " ,
abserr )
v a l e u r de l ’ i n t é g r a l e = 0 . 5 , e r r e u r en v a l e u r a b s o l u e =
5 . 5 5 1 1 1 5 1 2 3 1 2 5 7 8 3 e −15

Si on a besoin de passer d’autres paramètres à la fonction à intégrer, on peut utiliser


l’argument args de la fonction quad. Par exemple pour
Z 1
ax2 + bdx.
0

def f (x , a , b ) :
r e t u r n a * x ** 2+ b
a =2
b=1
I = i n t e g r a t e . quad ( f , 0 , 1 , a r g s = ( a , b ) )
p r i n t ( " I =" , I )
#resultat
I =(1.6666666666666667 , 1.8503717077085944 e −14)

On peut avoir besoin d’utiliser le symbol oo comme borne d’un intégral. Par exemple
Z oo
fn (x) = e−xt /t n dt.
1

def f ( t , n , x ) :
r e t u r n np . exp ( − x * t ) / t ** n

def expint (n , x ) :
r e t u r n i n t e g r a t e . quad ( f , 1 , np . i n f , a r g s = ( n , x ) )

print ( expint (3 , 1.0) )

Listing 7.18 – intégrale simple avec paramètre args

(0.10969196719780967 , 1.0256171336949145 e −08)

Listing 7.19 – resultat de l’intégrale simple


7.1 Numpy, matplotlib et scipy 125

PS. ll existe déjà une fonction predéfinie expn(n,x) dans le paquetage scipy.special (on
pourrait donc l’importer import scipy.special as special et utiliser special.expn(3,
1.0) dans l’exemple ci-dessus pour obtenir le même résultat.
Double intégration :
Z oo Z oo
I(n) = e−xt /t n dt dx.
0 1

def I ( n ) :
r e t u r n i n t e g r a t e . d b l q u a d ( lambda t , x : np . exp ( − x * t ) / t ** n , 0 , np . i n f ,
lambda x : 1 , lambda x : np . i n f )

p r i n t ( I ( 3 ) ) # " La v a l e u r de l ’ i n t é g r a l e e s t 1 / n "
print ( I (4) )

Listing 7.20 – intégrale double

(0.33333333325010883 , 1.3888461883425516 e −08)


(0.2500000000043577 , 1.2983033469368098 e −08)

Listing 7.21 – resultat de l’integrale double


Bibliographie

Articles
[7] E. Knuth D ONALD. “Fonction de hashage”. In : (oct. 2023).

Livres
[1] G. A LLAIRE. Analyse numérique et optimisation : une introduction à la modélisation
mathématique et à la simulation numérique. Ecole polytechnique : Mathématiques
appliquées. Editions de l’Ecole polytechnique, 2005. ISBN : 9782730212557. URL :
https://books.google.co.ma/books?id=vReEuE4margC.
[2] N. AUDFRAY et al. Informatique : MPSI, PCSI, PTSI, BCPST, MP, PC, PT, PSI,
TSI, TPC. Dunod, 2020. ISBN : 9782100816408. URL : https://books.google.
co.ma/books?id=7-33DwAAQBAJ.
[3] N. AUDFRAY et al. Informatique - Tronc commun MPSI-PCSI-PTSI-MP-PC-PSI-
PT. Ediscience, 2022. ISBN : 9782100849444. URL : https://books.google.co.
ma/books?id=sEuJEAAAQBAJ.
[4] T. AUDIBERT et A. O USSALAH. Informatique tronc commun - CPGE scienti-
fiques 1re et 2e années - Nouveaux programmes. Editions Ellipses, 2021. ISBN :
9782340055926. URL : https://books.google.co.ma/books?id=WCFEEAAAQBAJ.
[5] A. C AIGNOT et al. Informatique - Tronc commun : Prépas scientifiques - MPSI-
PCSI-PTSI-MP/MP*-PC/PC*-PSI/PSI*-PT/PT*... : Cours - Synthèse - Méthodes
détaillées - Exercices et sujets corrigés. Prépas scientifiques : Les essentiels. Vuibert,
2022. ISBN : 9782311213539. URL : https://books.google.co.ma/books?
id=K--cEAAAQBAJ.
128 Chapitre 7. calcul scientifique

[6] B. C LENET et B. T UCKFIELD. Au coeur des algorithmes : Les bases de la pro-


grammation avec Python. De Boeck Supérieur, 2023. ISBN : 9782807351899. URL :
https://books.google.co.ma/books?id=gVDUEAAAQBAJ (cf. pages 37, 41).
[9] J.C. F ILLIÂTRE et S. C ONCHON. Apprendre à programmer avec OCaml : Algo-
rithmes et structures de données. Noire. Eyrolles, 2014. ISBN : 9782212291551.
URL : https://books.google.co.ma/books?id=aTy9BAAAQBAJ (cf. pages 65,
71).
[10] J. G UILLOD. Programmation Python par la pratique : Problèmes et exercices
corrigés. Dunod, 2021. ISBN : 9782100819089. URL : https://books.google.
co.ma/books?id=gS4zEAAAQBAJ (cf. pages 25, 27, 29, 31, 33).
[12] S. JANNY et al. Informatique tronc commun - ITC - PSI, MP, PC. ELLIPSES, 2022.
ISBN : 9782340070776. URL : https://books.google.co.ma/books?id=
p4lzEAAAQBAJ.
[13] J.P. M UELLER et L. M ASSARON. Les algorithmes pour les Nuls grand format.
Pour les Nuls Informatique. edi8, 2017. ISBN : 9782412033036. URL : https :
//books.google.co.ma/books?id=7uUzDwAAQBAJ (cf. page 35).
[14] B. S ERGE. Informatique avec Python - 2e année prépa scientifique. ELLIPSES,
2017. ISBN : 9782340051218. URL : https://books.google.co.ma/books?
id=wh1EEAAAQBAJ.

Webographie
[8] Python Software F OUNDATION. Exceptions en Python. https://docs.python.
org/fr/3/tutorial/errors.html. Jan. 2024 (cf. page 106).
[11] Python Software F OUNDATION. Entré/Sortie en Python. https://docs.python.
org/fr/3/tutorial/inputoutput.html. Jan. 2024 (cf. page 104).
[15] Python Software F OUNDATION. Datat struct In Python. https://docs.python.
org/fr/3/tutorial/datastructures.html. Jan. 2024 (cf. pages 10, 19, 22).
Index

A Exercices . . . . . . . . . . . . . . . . . 25, 59, 72, 96


extend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
append . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 F

B fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
bloc mémoire . . . . . . . . . . . . . . . . . . . . . . 104 filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
find . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
C fonction récursive . . . . . . . . . . . . . . . . . . . 57
format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
capitalize . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
caractère d’échappement . . . . . . . . . . . . . 22 I
concaténation . . . . . . . . . . . . . . . . . . . . . . . 12
copy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 identity . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
count . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 immuable . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
insert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
D
J
dblquad . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
del . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 join . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
diag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
dict . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 L
dot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
duplication . . . . . . . . . . . . . . . . . . . . . . . . . 12 lambda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
legend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
E linspace . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Entrée/Sortie . . . . . . . . . . . . . . . . . . . . . . 103 lower. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24
130 INDEX

M tri à bulle . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
tril, triu . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 tuple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
matrice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
max . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 U
min . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
mutable . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 upper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

N Z
Numpy, matplotlib et scipy . . . . . . . . . . 111 zip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

P
Pile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
plot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
pop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
programmation modulaire . . . . . . . . . . . . 45

Q
quad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

R
recherche dichotomique . . . . . . . . . . . . . . 36
recherche séquentielle . . . . . . . . . . . . . . . 35
remove . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
replace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
reverse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

S
scatter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
slicing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
split . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
str . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
strip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
sum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

T
tampon mémoire . . . . . . . . . . . . . . . . . . . 104
transposé . . . . . . . . . . . . . . . . . . . . . . . . . . 117
tri par insertion . . . . . . . . . . . . . . . . . . . . . . 41
tri par sélection . . . . . . . . . . . . . . . . . . . . . 39

Vous aimerez peut-être aussi

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy