Académique Documents
Professionnel Documents
Culture Documents
2 - Piles-Files - Master-IESE - 2023 - 24 Vers2
2 - Piles-Files - Master-IESE - 2023 - 24 Vers2
Avancées
Par
Prof. B. AHIOD
(ahiod@fsr.ac.ma)
2023-2024
Objectifs
1
Types Abstraits de Données
(TADs)
Spécification & Implémentation
2
Définition d’un TAD
• Un TAD (Data Abstract Type) est un ensemble de valeurs muni d’opérations sur
ces valeurs, sans faire référence à une implémentation particulière.
• Exemples :
₋ Dans un algorithme qui manipule des entiers, on s’intéresse, non pas à la
représentation des entiers, mais aux opérations définies sur les entiers : +, -, *, /
₋ Type booléen, ensemble de 2 valeurs (faux, vrai) muni des opérations : non, et, ou
3
Signature d’un TAD
Exemple : TAD Booléen
Nom du
TAD
Type Booléen
Opérations Nom de l'opération
vrai : Booléen Deux arguments
faux : Booléen de type Booléen
non : Booléen Booléen Type valeur de
et : Booléen x Booléen Booléen retour
ou : Booléen x Booléen Booléen
• Précise :
₋ Les domaines de définition (ou d’application) des
opérations ;
₋ Les propriétés des opérations.
4
Exemple 1 de TAD
(TAD Booléen)
Type Booléen
Opérations
vrai : Booléen
faux : Booléen
non : Booléen Booléen
et : Booléen × Booléen Booléen
ou : Booléen × Booléen Booléen
Préconditions
Axiomes Aucune
Soit, a, b : Booléen précondition
non(vrai) = faux
non(non(a)) = a
vrai et a = a
faux et a = faux
a ou b = non(non(a) et non(b))
Exemple 2 de TAD
(TAD Vecteur)
Type Vecteur
Utilise Entier, Elément
Opérations
vect : Entier Vecteur
changer_ième : Vecteur x Entier x Elément Vecteur
ième : Vecteur x Entier Elément
taille : Vecteur Entier
Préconditions
vect(i) est_défini_ssi i ≥ 0
ième(v,i) est_défini_ssi 0 ≤ i < taille(v)
changer_ième(v,i,e) est_défini_ssi 0 ≤ i < taille(v)
Axiomes
Soit, i, j : Entier, e : Elément, v : Vecteur
si 0 ≤ i < taille(v) alors ième(changer_ième(v,i,e),i) = e
si 0 ≤ i < taille(v) et 0 ≤ j < taille(v) et i ≠ j
alors ième(changer_ième(v,i,e),j) = ième(v,j)
taille(vect(i)) = i
taille(changer_ième(v,i,e)) = taille(v)
Master IESE Structures de données avancées (2023-2024) 10
5
Opérateurs
• Trois catégories d'opérateurs (ou de primitives) :
Opérations Partielles
• Exemple :
Opérations ième et changer_ième du TAD Vecteur
6
Réutilisation des TADs
• Exemples :
Types Entier et Elément utilisés par le TAD Vecteur
7
Implémentation d’un TAD
• Pour implémenter un TAD :
₋ Déclarer la structure de données retenue pour représenter le TAD : L’interface
₋ Définir les opérations primitives dans un langage particulier : La réalisation
• Exigences :
₋ Conforme à la spécification du TAD ;
₋ Efficace en terme de complexité d’algorithme.
• Tout module ou programme principal qui a besoin d'utiliser les fonctions du module truc,
devra juste inclure le truc.h
8
Implémentation d’un TAD
Exemple : TAD Booléen
/* fichier Booleen.c */
Structures de Données
Linéaires
9
Objectifs
Les Piles
(Stacks)
10
Notion de Pile (Stack)
• Les piles sont très utilisées en informatique
• Notion intuitive :
₋ pile d'assiettes, pile de dossiers à traiter, …
Exemple de Pile
Empiler B Dépiler D
Empiler A Empiler C
Empiler E
Empiler D
11
Type Abstrait Pile
Type Pile
Utilise Elément, Booléen
Opérations
pile_vide : Pile
est_vide : Pile Booléen
empiler : Pile x Elément Pile
dépiler : Pile Pile
sommet : Pile Elément
Préconditions
dépiler(p) est-défini-ssi est_vide(p) = faux
sommet(p) est-défini-ssi est_vide(p) = faux
Axiomes
Soit, e : Element, p : Pile
est_vide(pile_vide) = vrai
est_vide(empiler(p,e)) = faux
dépiler(empiler(p,e)) = p
sommet(empiler(p,e)) = e
12
Représentation d'une Pile
• Représentation contiguë (par tableau) :
₋ Les éléments de la pile sont rangés dans un tableau
₋ Un entier représente la position du sommet de la pile
Pile Contiguë
Pile 6 /* Pile contiguë en C */
13
Spécification d'une Pile Contiguë
/* fichier "Tpile.h" */
#ifndef _PILE_TABLEAU
#define _PILE_TABLEAU
#include "Booleen.h"
typedef struct {
Element elements[MAX_PILE]; /* les éléments de la pile */
int sommet; /* position du sommet */
} Pile; type Pile : une structure à
deux champs
// Déclaration des fonctions gérant la pile
Pile pile_vide ();
Pile empiler ( Pile p, Element e );
Pile depiler ( Pile p );
Element sommet ( Pile p );
Booleen est_vide ( Pile p );
#endif
#include "Tpile.h"
// ajout d'un élément
// Définition des fonctions gérant la pile Pile empiler(Pile p, Element e) {
if (p.sommet >= MAX_PILE-1) {
// initialiser une nouvelle pile printf("Erreur : pile pleine !\n");
Pile pile_vide() { exit(-1);
Pile p; }
p.sommet = -1; (p.sommet)++;
return p; (p.elements)[p.sommet] = e;
} return p;
}
// tester si la pile est vide
Booleen est_vide(Pile p) { // enlever un élément
if (p.sommet == -1) return vrai; Pile depiler(Pile p) {
return faux; /* pré-condition : pile non vide !*/
} if (est_vide(p)) {
printf("Erreur: pile vide !\n");
// Valeur du sommet de pile exit(-1);
Element sommet(Pile p) { }
/* pré-condition : pile non vide ! */ p.sommet--;
if (est_vide(p)) { return p;
printf("Erreur: pile vide !\n"); }
exit(-1);
}
return (p.elements)[p.sommet];
}
14
Exemple d'Utilisation d'une Pile Contiguë
/* fichier "UTpile.c" */
#include <stdio.h>
#include "Tpile.h"
int main () {
Pile p = pile_vide();
p = empiler(p,50);
p = empiler(p,5);
p = empiler(p,20);
p = empiler(p,10);
printf("%d au sommet après empilement de 50, 5, 20 et"
" 10\n", sommet(p));
p = depiler(p);
p = depiler(p);
printf("%d au sommet après dépilement de 10 et 20\n",
sommet(p));
return 0;
}
Pile chaînée
10 20 // type Cellule
typedef struct cellule {
element valeur;
struct cellule *suivant;
p Pointeur } Cellule;
NULL
Cellule contenant
la valeur 5 // type Pile
50
typedef Cellule *Pile;
Pointeur sur cellule
suivante
Master IESE Structures de données avancées (2023-2024) 30
15
Spécification d'une Pile Chaînée
/* fichier "Cpile.h" */
#ifndef _PILE_CHAINEE
#define _PILE_CHAINEE
#include "Booleen.h"
#endif
Master IESE Structures de données avancées (2023-2024) 31
16
Exemple d'Utilisation d'une Pile Chaînée
/* fichier "UCpile.c" */
#include <stdio.h>
#include "Cpile.h"
int main () {
Pile p = pile_vide();
p = empiler(p,50);
p = empiler(p,5);
p = empiler(p,20);
p = empiler(p,10);
printf("%d au sommet après empilement de 50, 5, 20 et"
" 10\n", sommet(p));
p = depiler(p);
p = depiler(p);
printf("%d au sommet après dépilement de 10 et 20\n",
sommet(p));
return 0;
}
Complexité
17
Applications d'une Pile
Exemples (1)
• Vérification du bon équilibrage d’une expression parenthèsée :
₋ Pour vérifier qu'une expression parenthésée est équilibrée, à chaque
rencontre d'une parenthèse ouvrante on l'empile et à chaque rencontre
d'une parenthèse fermante on dépile ;
18
Exercices
1. Ecrire un programme C qui implémente une pile d’entiers. Ce programme affiche à
l'utilisateur un menu avec les options suivantes :
1. empiler un entier dans la pile ;
2. dépiler un entier de la pile ;
3. taille de la pile ;
4. sommet de la pile ;
5. afficher le contenu de la pile ;
6. quitter le programme.
2. Ecrire un programme C qui lit une séquence de nombres entiers et l’affiche dans l’ordre
inversé. Indication : Utiliser une pile.
3. [Enoncé TP2] Ecrire un programme C permettant de vérifier si une expression
arithmétique contenant les délimiteurs [, }, ), {, ( et ], est correcte ou non
Exemples :
{x + (100 - [a + b]) - d} est une expression correcte.
{x + (y - [a + b]) * 20 - [d + c} est une expression incorrecte.
Les Files
(Queues)
19
Notion de File (Queue)
• Les files sont très utilisées en informatique
• Notion intuitive :
₋ File d'attente à un guichet, file de documents à imprimer, …
Exemple de File
Enfiler A
Enfiler E Défiler B
Enfiler B
Enfiler C
Enfiler D
20
Type Abstrait File
Type File
Utilise Elément, Booléen
Opérations
file_vide : File
est_vide : File Booléen
enfiler : File x Elément File
défiler : File File
tête : File Elément
Préconditions
défiler(f) est-défini-ssi est_vide(f) = faux
tête(f) est-défini-ssi est_vide(f) = faux
Axiomes
Soit, e : Element, f : File
est_vide(pile_vide) = vrai
est_vide(enfiler(f,e)) = faux
si est_vide(f) = vrai alors tête(enfiler(f,e)) = e
si est_vide(f) = faux alors tête(enfiler(f,e)) = tête(f)
si est_vide(f) = vrai alors défiler(enfiler(f,e)) = file_vide
si est_vide(f) = faux
alors défiler(enfiler(f,e)) = enfiler(défiler(f),e)
21
Représentation d'une File
• Représentation contiguë (par tableau) :
₋ Les éléments de la file sont rangés dans un tableau
₋ Deux entiers représentent respectivement les positions de la tête
et de la queue de la file
• Inconvénient :
₋ On ne peut plus ajouter des éléments dans la file, alors qu'elle n'est
pas pleine !
22
Représentation Contiguë d'une File
(par tableau simple) (1)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
tab tab 5 2 10 20 30 40 50
tete -1 tete -1
queue -1 File initialement vide de queue 6 File après ajout de 5, 2,
taille maximale = 10 10, 20, 30, 40 et 50
(1) (2)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
tab 10 20 30 40 50 tab
tete 1 tete 6
queue 6 File après suppression queue 6 File après suppression
de 5 et 2 de 10, 20, 30, 40 et 50
(3) (4)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
tab tab 5 15 10
tete 6 tete 6
queue 6 queue 9 File après ajout de
File vide 5, 15 et 10
(5) (6)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
tab 10 tab 10
tete 8 tete 8
queue 9 File après queue 9 On ne peut plus
suppression 5 et 15 ajouter dans la file !!
(7) (8)
23
File Contiguë
/* File contiguë en C */
File
// taille maximale file
#define MAX_FILE 10
0 1 2 3 4 5 6 7 8 9
tab 10 20 30 40 50
// type des éléments
tete 1 typedef int Element;
queue 6 Tableau de taille
maximale 10 // type File
typedef struct {
Position qui précède le Element tab[MAX_FILE];
premier élément de la file
int tete;
int queue;
Position du dernier
} File;
élément de la file
#include "Booleen.h"
typedef struct {
Element tab[MAX_FILE]; /* les éléments de la file */
int tete; /* position précédant premier élément */
int queue; /* position dernier élément */
} File; type File : une structure à
trois champs
// Déclaration des fonctions gérant la pile
File file_vide ();
File enfiler ( File f, Element e );
File defiler ( File f );
Element tete ( File f );
Booleen est_vide ( File f );
#endif
24
Réalisation d'une File Contiguë
/* fichier "Tfile.c" */
#include "Tfile.h"
// ajout d'un élément
// Définition des fonctions gérant la file File enfiler(File f, Element e) {
if (f.queue == MAX_FILE-1) {
// initialiser une nouvelle file printf("Erreur: on ne peut ajouter !\n");
File file_vide() { exit(-1);
File f; }
f.queue = f.tete = -1; (f.queue)++;
return f; (f.tab)[f.queue] = e;
} return f;
}
// tester si la file est vide
Booleen est_vide(File f) { // enlever un élément
if (f.tete == f.queue) return vrai; File defiler(File f) {
return faux; /* pré-condition : file non vide !*/
} if (est_vide(f)) {
printf("Erreur: file vide !\n");
// Valeur en tête de file exit(-1);
Element tete(File f) { }
/* pré-condition : file non vide ! */ f.tete++;
if (est_vide(f)) { return f;
printf("Erreur: file vide !\n"); }
exit(-1);
}
return (f.tab)[f.tete+1];
}
Master IESE Structures de données avancées (2023-2024) 49
• Inconvénient :
₋ décalage très coûteux, si la file contient beaucoup d'éléments
25
Représentation Contiguë d'une File
(par tableau simple avec décalage) (1)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
tab tab 5 2 10 20 30 40 50
tete -1 tete -1
queue -1 File initialement vide de queue 6 File après ajout de 5, 2,
taille maximale = 10 10, 20, 30, 40 et 50
(1) (2)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
tab 10 2 30 40 50 tab
0
tete -1 tete -1
queue 4 File après suppression queue -1 File après suppression
de 5 et 2 de 10, 20, 30, 40 et 50
(3) (4)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
tab tab 5 15 10
tete -1 tete -1
queue -1 queue 2 File après ajout de
File vide 5, 15 et 10
(5) (6)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
tab 10 tab 10 5 6 20 8 35 25 33 4 80
tete -1 tete 8
File après Après ajout de 5, 6, 20, 8,
queue 0 queue 9
suppression 5 et 15 35, 25, 33, 4 et 80, File
(7) (8) pleine!!
26
Représentation Contiguë d'une File
(Par tableau circulaire)
27
Représentation Contiguë d'une File
(par tableau circulaire) (1)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
tab tab 5 2 10 20 30 40 50
tete 0 tete 0
File initialement vide
queue 0 queue 7 File après ajout de 5, 2,
qui peut contenir au
10, 20, 30, 40 et 50
(1) plus 9 éléments (2)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
tab 10 20 30 40 50 tab
tete 2 tete 7
queue 7 File après suppression queue 7 File après suppression
de 5 et 2 de 10, 20, 30, 40 et 50
(3) (4)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
tab tab 10 5 15
tete 7 tete 7
queue 7 queue 0 File après ajout de
File vide 5, 15 et 10
(5) (6)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
tab 10 15 tab 10 5 6 20 8 35 25 33 15
tete 8 tete 8
File après Après ajout de 5, 6, 20, 8,
queue 0 queue 7
suppression 5 35, 25, et 33,
(7) (8) File pleine!!
28
Réalisation d'une File Contiguë Circulaire
/* fichier "TCfile.c" */
#include "Tfile.h"
f.queue = f.tete = 0; }
} (f.tab)[f.queue] = e;
return f;
Booleen est_vide(File f) {
if (f.tete == f.queue) return vrai; // enlever un élément
return faux; File defiler(File f) {
exit(-1); }
}
return (f.tab)[(f.tete+1) % MAX_FILE];
}
File chaînée
10 20 // type Cellule
typedef struct cellule {
element valeur;
struct cellule *suivant;
tete Pointeur } Cellule;
queue NULL
// type File
50 typedef struct {
struct cellule *tete;
Cellule contenant struct cellule *queue;
Queue de file
la valeur 30
pointée par queue } File;
Master IESE Structures de données avancées (2023-2024) 58
29
Spécification d'une File Chaînée
/* fichier "Cfile.h" */
#ifndef _FILE_CHAINEE
#define _FILE_CHAINEE
#include "Booleen.h"
#endif
30
Complexité
31
Exercices
1. Supposons que les contenus de la file F1 et la file F2 sont donnés. Quel est le contenu de la file F3 après
execution du code C ci-dessous ?. Le contenu de chaque file est affiché de sa tête (à gauche) à sa queue
(à droite). F1 : 42 30 41 31 19 20 25 14 10 11 12 15 F2 : 4 5 4 10 13
F3 = file_vide() ;
cpt = 0 ;
wile(( !est_vide(F1) et !est_vide(F2)) {
cpt += 1 ;
x = tete(F1) ;
F1 = defiler(F1) ;
y = tete(F2) ;
F2 = defiler(F2) ;
if (y == cpt) ;
F3 enfiler(F3, x) ;
}
2. [Enoncé TP3] Ecrire un programme C qui implémente une file (chaînée) d’entiers. Ce programme
affiche à l'utilisateur un menu avec les options suivantes :
1. enfiler un entier dans la file ;
2. défiler un entier de la file ;
3. taille de la file ;
4. tête de la file ;
5. afficher le contenu de la file ;
6. quitter le programme.
3. En utilisant les opérations de base sur les files, écrire une fonction C permettant de retourner le
minimum d’une file non vide d’entiers.
4. Ecrire un programme C pour inverser le contenu d’une file d’entiers. Indication : Utiliser une pile
Les Listes
(Lists)
32
Notion de Liste (List) (1)
• Généralisation des piles et des files
₋ Structure linéaire dans laquelle les éléments peuvent être traités les uns à
la suite des autres
₋ Ajout ou retrait d'éléments n’importe où dans la liste
₋ Accès à n'importe quel élément
• Exemple :
₋ une liste de 5 entiers L = <4, 1, 7, 3, 1> (place de rang 1 contient la valeur 4)
₋ une liste vide L2 = <>
Master IESE Structures de données avancées (2023-2024) 65
33
Exemples de Liste
Liste vide
34
Type Abstrait Liste (2)
Axiomes
Soit, e : Elément, l, l' : Liste, k, j : Entier
succ(l,accès(l,k)) = accès(l,k+1)
contenu(l,accès(l,k)) = kème(l,k)
Axiomes
Soit, e : Element, l, l' : Liste, k, j : Entier
si k ≤ longueur(l)
alors kème(concaténer(l,l'),k)= kème(l,k)
sinon kème(concaténer(l,l'),k)= kème(l',k-longueur(l))
35
Opérations sur une Liste (1)
• liste_vide : Liste
Opération d'initialisation ; la liste créée est vide
36
Opérations Auxiliaires sur une Liste
37
Liste Contiguë (Contiguous List)
/* Liste contiguë en C */
typedef struct {
element tab[MAX_LISTE]; // les éléments de la liste
int taille; // nombre d'éléments dans la liste
} Liste;
type Liste : une
// Déclaration des fonctions gérant la liste
Liste liste_vide (void);
structure à deux champs
int longueur (Liste l);
Liste inserer (Liste l, int i, element e);
Liste supprimer (Liste l, int i);
element keme (Liste l, int k);
#endif
38
Réalisation d'une Liste Contiguë (1)
Liste liste_vide(void) {
Liste l;
l.taille = 0;
return l;
}
Liste supprimer(Liste l, int i) {
// précondition : 0 ≤ i < longueur(l)
int longueur(Liste l) {
int r;
return l.taille;
if (i<0 || i>longueur(l)-1) { printf("Erreur : rang non
} valide !\n");
exit(-1);
Liste inserer(Liste l, int i, element e) { }
// précondition : longueur(l) = MAX_LISTE for (r = i; r<longueur(l)-1;; r++) l.tab[r] = l.tab[r+1];
// et 0 ≤ i < longueur(l)+1 (l.taille)--;
int r; return l;
if (longueur(l) == MAX_LISTE) { }
printf("Erreur : liste saturée !\n");
exit(-1); element keme(Liste l, int k) {
} // pas de sens que si 0 ≤ k ≤ longueur(l)-1
if (i<0 || i>longueur(l)) { if (k<0 || k>longueur(l)-1) {
printf("Erreur : rang non valide !\n"); printf("Erreur : rang non valide !\n");
exit(-1); exit(-1);
} }
for (r = longueur(l); r>i; r--) return l.tab[k];
l.tab[r] = l.tab[r-1]; }
l.tab[i] = e;
(l.taille)++;
return l;
}
39
Représentation Chaînée d'une Liste
• Les éléments ne sont pas rangés les uns à côté des autres
₋ La place d'un élément est l'adresse d'une structure qui contient
l'élément ainsi que la place de l'élément suivant
₋ Utilisation de pointeurs pour chaîner entre eux les éléments
successifs
// type Cellule
L Pointeur typedef struct cellule {
NULL element valeur;
struct cellule *suivant;
} Cellule;
Cellule contenant 50
la valeur 30 // type Liste
Dernier élément de typedef Cellule *Liste;
la liste
Master IESE Structures de données avancées (2023-2024) 80
40
Spécification d'une Liste Chaînée
/* fichier "CListe.h" */
#ifndef _LISTE_CHAINEE
#define _LISTE_CHAINEE
#endif
41
Réalisation d'une Liste Chaînée (2)
element contenu(Liste l, Place p) {
// pas de sens si longueur(l)=0 (liste vide)
if (longueur(l) == 0) {
printf("Erreur: liste vide !\n"); Liste supprimer(Liste l, int i) {
} int j;
} if (i<0 || i>longueur(l)+1) {
printf("Erreur: rang non valide!\n");
if (p->suivant == NULL) { if (i == 0) {
exit(-1); l=l->suivant;
} }
} Place q;
q=acces(l,i-1);
if (k<0 || k>longueur(l)-1) { }
exit(-1); return l;
} }
Remarques (1)
42
Remarques (2)
Liste ajouter(Liste l,
Place p, element e) { Liste enlever(Liste l, Place p) {
Liste pc; // p pointe élément à supprimer
pc=(Liste)malloc(sizeof(Cellule)); Place pred; //pred pointe avant p
if (pc == NULL) { if (p == l)
printf("Erreur: Problème de " l = succ(l,p);
"mémoire\n"); else {
exit(-1); pred=l;
while (succ(l,pred) != p)
}
pred = succ(l,pred);
pc->valeur = e;
pred->suivant = p->suivant;
pc->suivant = p->suivant;
}
p->suivant = pc free(p);
return l; return l;
} }
• Liste triée
43
Liste avec Tête Fictive
Liste Circulaire
44
Liste Doublement Chaînée
Liste Triée
10 15 20
45
Complexité
46
Liste Chaînée par Curseurs
/* Liste chaînée en C */
Liste valeur suivant // taille maximale liste
0 10 -1 #define MAX_LISTE 7
•…
47
Exercices
1. Après avoir implémenté en C la structure de données Liste chaînée pour les entiers,
programmer une fonction main pour tester une liste d'entiers. Le programme
affiche à l'utilisateur un menu avec les options suivantes :
1. insérer un entier dans la liste ;
2. supprimer un élément de la liste ;
3. taille de la liste ;
4. consulter un élément de la liste ;
5. inverser le contenu de la liste ;
6. purger la liste (i.e., enlever les doublons de la liste) ;
7. afficher le contenu de la liste ;
8. quitter le programme.
48