Académique Documents
Professionnel Documents
Culture Documents
2022-2023. Semestre 3
– Cours –
Chapitre 03 : Structures de données linéaires : Liste, Pile et
File
Partie01: Introduction aux Types Abstraits de Données (TAD)
Objectifs du cours
Objectif 1: Cette première partie du cours permet d'initier les étudiants au
concept de Type Abstrait de Données (TAD),
A quoi sert un TAD ?
Comment s'en servir?
Pourquoi recourir au TAD dans l'élaboration des algorithmes.
1. Introduction
1.1. Structures de Données (S.D): Moyen pour stocker et organiser les données pour en
faciliter l’accès et la modification.
Les trois premières notions définissent la Signature d’un TAD, les propriétés sont exprimées
généralement sous forme d’axiomes (formules) dans un TAD
2.1. Signature
Les sortes ne sont rien d’autre que des noms servant à représenter des ensembles de valeurs sur
lesquels vont porter les opérations. Par exemple naturel, booleen, entier, etc.
Chaque opération est définie par son profil : les sortes de ses paramètres et la sorte du résultat.
La forme générale du profil d’une opérations n-aire est:
Nom-opération : sorte1, sorte2, ..., sorten → sorter.
Exemples de signature: Les signatures suivantes sont extraites des TADs BOOLEEN et NATUREL:
TAD BOOLEEN
Sorte booléen TAD NATUREL
Opérations Sorte nat
vrai : → booléen Opérations
faux : → booléen
0 : → nat
_ et _ : booléen, booléen → booléen
succ : nat → nat
_ ou _ : booléen, booléen → booléen
_ + _ : nat , nat → nat
_ - _ : nat , nat → nat
_ * _ : nat , nat → nat
_ ^_ : nat , nat → nat
non_: booléen → booléen
La signature sert à définir les régles d'écriture des données. Par exemple, à l'aide des signatures
précédentes, nous pouvons affirmer ou non que les données suivantes sont correctes
syntaxiquement.
Remarque:
Plusieurs notations peuvent être utilisées pour représenter les données à l'aide des opérations d'une
signature:
Notation Mixfixée, les arguments sont situées de part et d'autre du nom de l'opération (
ex: a+b, c*d, _et_, ...), le "_" désigne la position de l'argument.
Notation Infixée, les arguments sont situées avant le nom de l'opération ( ab+, cd*
Notation Préfixée, les arguments sont situées après le nom de l'opération (succ(a),
non(d) ), dans ce cas, nous utilisons généralement les parenthèses pour les séparer du nom
de l'opération.
.
2.2. Réutilisation d'un TAD
Dans une signature, on appelle sorte(s) définie(s), les sortes correspondant aux noms de sortes
nouveaux.
On appelle sorte(s) prédéfinie(s), les sortes provenant des TADs utilisés.
Une opération est dite interne constructeur si elle rend un résultat d’une sorte définie. Ces
opérations servent à construire les valeurs d’une sorte. Par exemple, l’opération ”succ” dans le
TAD NATUREL, permet de construire tous les entiers.
Une opération est dite interne non constructeur si elle rend un résultat d’une sorte définie mais
ne construit pas de nouvelles valeurs pour cette sorte. Par exemple, l’opération ”_+_” dans le
TAD NATUREL.
Enfin, une opération est dite observateur sur une sorte définie si elle rend un résultat d’une sorte
prédéfinie et possède au moins un argument de sorte définie. Par exemple, l’opération ”_=_”
dans le TAD NATUREL1 ci dessous,
TAD NATUREL1
Utilise BOOLEEN
Sorte nat
Opérations
0 : → nat
succ : nat → nat Internes constructeurs
Les propriétés des opérations définies dans un TAD sont données sous formes d'axiomes. Les
axiomes servent souvent à donner une signification (une sémantique) aux sortes et opérations
de la signature. La forme générale de l’écriture des axiomes est:
termegauche ≡ termedroit
Le symbole ”≡” doit se lire comme est ”équivalent en sens à”, il n’a pas de direction privilégiée.
Cette forme peut s’étendre à l’expression des axiomes conditionnels comme suit:
Exemples d’axiomes
Si on veut complèter le TAD NATUREL par des axiomes, Il faut écrire pour chaque opération
observateur ou interne non constructeur (_+_, _-_, etc.), autant d’axiomes que d’opérations
internes constructeurs (0 et succ) combinées avec les arguments associés, c.-à-d. quatre axiomes
pour l’opération _+_.
0 + 0 ≡ 0;
0 + succ(Y) ≡ succ(Y);
succ( X) + 0 ≡ succ(X);
succ(X) + succ(Y) ≡ succ(X + succ(Y));
qui sont combinés deux à deux pour donner les axiomes 1 et 2 suivants.
Axiomes
1- X + 0 ≡ X;
2- X + succ(Y) ≡ succ(X + Y);
Etant données d1, d2, d3, d4 des valeurs de données du TAD NATUREL (ci dessus), sachant que:
d1= succ(0)+succ(succ(0)),
d2=succ(succ(0,0)),
d3=succ(succ(0))+1,
d4=succ(succ(succ(0))),
D'une part, on peut vérifier aisément que seules d1 et d4 sont correctes syntaxiquement par
rapport à la signature du TAD NATUREL présentée précedemment.
Dans d2, l’opération succ est utilisée avec deux arguments au lieu d’un seul, la donnée d3 utilise un
terme “1” qui n’est pas spécifié dans la signature correspondante.
D'autre part et selon ces deux axiomes, on peut déduire que la donnée d1 a le même
sens que d4, malgré qu’elles sont écrites différemment. On applique l’axiome 2, deux fois de
suite à la donnée d1, suivi de l’application de l’axiome 1, on retrouve d4. L'application d'un
axiome consiste à instantier la donnée en question avec son terme gauche, faire les substitutions
nécessaires des différentes variables, et remplacer alors cette donnée par son équivalent défini par le
terme droit de l'axiome.
Remarques:
1. Nous tenons à remarquer que les axiomes données pour exprimer la sémantique de
l'opération _-_ du TAD NATUREL peuvent être changés et simplifiés en insérant une clause
précondition dans le TAD en question, afin de restreindre (limiter) le domaine de
définition des arguments de cette opération. Il s'agit de définir cette opération: x-y
uniquement pour x ≥ y. La précondition d'une opération s'écrit ainsi:
Précondition
x-y définie ssi x ≥ y
Axiomes
...
X - 0 ≡ X;
succ(X) - succ(Y) ≡ X - Y;
...
2. Nous résumons dans ce qui suit les TAD NATUREL et BOOLEEN qui décrivent les données de type
entiers positifs et les données booléennes ainsi que les propriétes des opérations à faire sur ces
données.
TAD NATUREL
TAD BOOLEEN
Sorte nat
Sorte booléen
Opérations
Opérations
0 : → nat
vrai : → booléen
succ : nat → nat
faux : → booléen
_ + _ : nat , nat → nat
_ et _ : booléen, booléen → booléen
_ - _ : nat , nat → nat
_ ou _ : booléen, booléen → booléen
_ * _ : nat , nat → nat
non_: booléen → booléen
_ ^_ : nat , nat → nat (puissance)
Variables b: booléen
Variables X, Y : nat
Axiomes
Précondition
1- non vrai ≡ faux;
2- non faux ≡ vrai; X-Y définie ssi X Y (convention
3- vrai et b ≡ b; pour éviter de sortir des entiers
4- faux et b ≡ faux; naturels)
5- vrai ou b ≡ vrai; Axiomes
6- faux ou b ≡ b; 1- X + 0 ≡ X;
2- X + succ(Y) ≡ succ(X + Y);
3- 0 - X ≡ 0;
4- X - 0 ≡ X;
5- succ(X) - succ(Y) ≡ X - Y;
6- X * 0 ≡ 0;
7- X * succ(Y) ≡ X + (X * Y);
8- X ^0 ≡ succ(0);
9- X ^succ(Y) ≡ X * (X ^Y);
1.2 Intérêt et implémentation d'un TAD
Nous notons l'intérêt de spécifier (décrire) les Structures de Données (S.D) utilisées dans
un algorithme avec un TAD à travers l'exemple ci dessous. Nous montrons comment passer
d'une telle spécification (définition ou description) à son implémentation (en
algorithmique) ou sa codification au niveau d'un programme en utilisant n'importe quel
langage de programmation.
Exercice 1
Nous considérons la structure de données "complexe" qui organise les données
de type "nombres complexes". Le TAD correspondant peut être donné par:
TAD COMPLEXE
Utilise REEL
Sorte complexe
Opérations
constC : réel, réel → complexe Interne constructeur
rl : complexe → réel
im : complexe → réel
module: complexe → réel Observateurs
... /* Nous pouvons tjs enrichir un TAD par d’autres Opérations (O.P)
Variables
r1, r2, r3, r4 : réel,
z, z1, z2 : complexe
Axiomes
1- rl(constC(r1,r2)) ≡ r1 /* Constructeur en partie gauche
2- im(constC(r1,r2)) ≡ r2
3- module((constC(r1,r2)) ≡ sqrt(r1*r1 + r2*r2)) Sachant que les opérations +, * et sqrt
sont définies dans le TAD
REEL
On peut écrire d'une autre manière ces 3 derniers axiomes: (cette manière favorise la
réutilisation de l’axiome à l’implémentation et elle consiste à utiliser des variables ds la
partie gauche de l’axiome et non des opérations constructeur (ds la partie droite les
opérations constructeur sans pbm)
module(z) ≡ sqrt(rl(z)*rl(z) + im(z)*im(z)))
addC(z1,z2) ≡ constC(rl(z1)+rl(z2), im(z1)+im(z2))
soustC(z1,z2) ≡ constC(rl(z1)-rl(z2), im(z1)-im(z2))
Cette 2eme forme n’utilise pas les constructeurs ds les arguments (partie gauche, mais des
variables de la sorte définie, ici Z: complexe) et elle permet ainsi d’utiliser l’axiome à
l’implémentation; c’est la forme qu’il faut tjs tnter de trouver.
L'implémentation proposée repose sur la représentation interne des complexes par les
enregistrements.