Vous êtes sur la page 1sur 69

Module: Programmation II

Filière: SMA-S4

Listes Chainées, Piles, Files


Pr. Issam QAFFOU
Laboratoire Ingénierie des Systèmes d’Information
Département d’Informatique
FSSM-UCA

Version 2015/2016
(Printemps)
Introduction
• Une liste chainée est un ensemble fini
d’éléments enchainés.
• Les éléments d’une chaines s’appellent des
maillons (ou nœud, élément, etc.).
• Chaque maillon est constitué de deux parties:
données et pointeur.
• Le pointeur enchaine un maillon à son suivant.
• Vous pouvez simuler les listes chainées à un
train.
28/03/2016 Langage C 2 / 69
Introduction
• Une liste chainée est une structure de données qui
change durant l’exécution.
– Les maillons successifs sont connectés par des pointeurs.
– Le dernier élément pointe sur NULL.
– Elle peut augmenter ou diminuer en taille lors de
l'exécution d'un programme.
– Elle ne perd pas d'espace mémoire.
Tête

A B C

28/03/2016 Langage C 3 / 69
Introduction

• Garder la trace d’une liste chainée:


– On doit connaitre le pointeur sur le 1er élément
de la liste (appelé début, tête, etc.).

• Les listes chainées sont flexibles en ajout


d’éléments pour être réarrangées
efficacement.
– Insérer un élément.
– Supprimer un élément.

28/03/2016 Langage C 4 / 69
Illustration: Insertion

A B C

Élément à
X insérer

A B C

28/03/2016 Langage C 5 / 69
Illustration: Suppression
Élément à supprimer
A B C

A B C

28/03/2016 Langage C 6 / 69
Introduction
• Insertion:
– Un enregistrement (maillon, noeud, etc.) est créé en
maintenant le nouvel élément.
– Le pointeur suivant du nouvel enregistrement est
configuré pour le lier à l'élément qui le suit dans la
liste.
– Le pointeur suivant de l'élément qui doit précéder
doit être modifié pour pointer vers le nouvel
élément.
• Suppression:
– Le pointeur suivant de l’élément qui précède
immédiatement celui à supprimer est modifié pour
pointer vers le suivant de l’élément supprimé.
28/03/2016 Langage C 7 / 69
Tableaux Vs Listes Chainées
• Les tableaux sont appropriés à:
– Insérer/supprimer un élément à la fin.
– Accéder directement à n’importe quel élément
• Les listes chainées sont appropriées à:
– Insérer un élément.
– Supprimer un élément
– Des applications où l’accès séquentiel est
demandé.
– Des applications où le nombre d’éléments ne
pourra pas être connu exactement au début.

28/03/2016 Langage C 8 / 69
Types de listes
• En fonction de la manière dont chainage est
utilisé pour maintenir l’adjacence, plusieurs
types différents de listes chaînées sont
possibles.
– Listes linéaires
• Celles que nous avons discutées jusqu'à présent.
tête

A B C

28/03/2016 Langage C 9 / 69
Types de listes

– Listes circulaires
• Le pointeur du dernier élément de la liste pointe vers le
premier élément.
tête

A B C

28/03/2016 Langage C 10 / 69
Types de listes

– Listes doublement chainées


• Deux pointeurs existent entre les nœuds adjacents dans
les deux sens.
• La liste peut être parcourue en avant ou en arrière.
• Habituellement, deux pointeurs sont maintenus pour
garder une trace de la liste, la tête et la queue.
tête queue

A B C

28/03/2016 Langage C 11 / 69
Opérations basiques

• Création d’une liste


• Parcourir une liste
• Insertion d’un élément dans une liste
• Supprimer un élément d’une liste
• Concaténer deux listes en une

28/03/2016 Langage C 12 / 69
Type abstrait de données
• C’est quoi un type abstrait de données?
– C’est un type de données défini par le programmeur
– Typiquement plus complexe que les types de données
simples comme int, float, etc.
• Pourquoi abstrait?
– Parce que les détails de l’implémentation son cachés
– Quand on fait quelques opérations (comme
insertion), on appelle simplement une fonction.
– Des détails de comment la liste est implémentée ou
comment la fonction insérer() est écrites ne sont plus
nécessaires.

28/03/2016 Langage C 13 / 69
Étude de cas
• Tout noeud est une structure (type abstrait).
• Soit la structure d’un noeud comme suit:
struct stud {
int code;
char nom[25];
int age;
struct stud *suiv;
};

/* un type de donnée défini appelé “noeud” */


typedef struct stud noeud;
noeud *tete;

28/03/2016 Langage C 14 / 69
Création d’une liste
Comment débuter?
• Pour commencer, nous devons créer un nœud
(le premier nœud), et de faire tete pointer sur
lui.
tete=(noeud*)malloc(sizeof(noeud));

code
suiv
nom
tete
age

28/03/2016 Langage C 16 / 69
Comment débuter? …
• S'il y a n nombre de nœuds dans la liste
chaînée initiale:
– Allouer n enregistrements, un par un.
– Lire les champs des enregistrements
– Modifier les chainages des noeuds pour que la
chaine soit formée.
tete

A B C

28/03/2016 Langage C 17 / 69
noeud *creer_liste()
{
int k, n;
noeud *p, *tete;
printf ("\n Combien d’elements?");
scanf ("%d", &n);
for (k=0; k<n; k++)
{
if (k == 0) {
tete= (noeud *) malloc(sizeof(noeud));
p = tete;
}
else {
p->suiv= (noeud *) malloc(sizeof(noeud));
p = p->suiv;
}
scanf ("%d %s %d", &p->code, p->nom, &p->age);
}
p->suiv = NULL;
return (tete);
}

28/03/2016 Langage C 18 / 69
Appel dans le main()

• Appeler à partir de la fonction main():


noeud *tete;
………
tete= creer_liste();

28/03/2016 Langage C 19 / 69
Parcourir une liste
Quoi faire?

• Une fois la liste chainée a été construite et


tete pointe sur le 1er élément de la liste,
– Suivre les pointeurs
– Afficher les contenus des noeuds comme ils sont
parcourus.
– S’arrêter quand le pointeur suiv pointe vers NULL.

28/03/2016 Langage C 21 / 69
void afficher(noeud *tete)
{
int count = 1;
noeud *p;

p = tete;
while (p != NULL)
{
printf ("\nNoeud %d: %d %s %d", count,
p->code, p->nom, p->age);
count++;
p = p->suiv;
}
printf ("\n");
}

28/03/2016 Langage C 22 / 69
• Appeler à partir de la fonction main():

noeud *tete;
………
afficher(&tete);

28/03/2016 Langage C 23 / 69
Insérer un noeud dans une liste
Comment?

• Le problème est d’insérer un noeud avant un


noeud spécifique.
– Spécifique veut dire une certaine valeur donnée
au noeud (appelée clé)
– Dans cet exemple, on la considère code.
• Convention:
– Si la valeur de code donnée est négative, le noeud
sera inséré à la fin de la liste.

28/03/2016 Langage C 25 / 69
Continuer…
• Quand un noeud est ajouté au début,
– Seulement un seul pointeur suiv devra être
modifié.
• Tete pointera sur le nouveau noeud.
• Le nouveau noeud pointera sur l’ex premier élément.
• Quand un noeud est ajouté à la fin,
– Deux pointeurs suiv seront modifiés
• Le dernier noeud pointe sur le noeud ajouté
• Le nouveau noeud pointe sur NULL.
• Quand un noeud est ajouté au milieu,
– Deux pointeurs suiv seront modifiés
• Le noeud précédent pointe sur le noeud ajouté
• Le nouveau noeud pointe sur le noeud suivant.

28/03/2016 Langage C 26 / 69
void inserer (noeud **tete)
{
int k = 0, c1;
noeud *p, *q, *new;

new = (noeud *) malloc(sizeof(noeud));

printf ("\nDonnee a inserer: ");


scanf ("%d %s %d", &new->code, new->nom, &new->age);
printf ("\nInserer avant code: ");
scanf ("%d", &c1);

p = *tete;

if (p->code== c1) /* Au début*/


{
new->suiv= p;
*tete= new;
}

28/03/2016 Langage C 27 / 69
else
{
while ((p != NULL) && (p->code!= c1))
{
q = p;
p = p->suiv;
}
Les pointeurs p et
if (p == NULL) /* à la fin */
q pointent toujours
{
sur des nœuds
q->suiv= new;
consécutifs.
new->suiv= NULL;
}
else if (p->code == c1)
/* au milieu*/
{
q->suiv= new;
new->suiv= p;
}
}
}

28/03/2016 Langage C 28 / 69
• Appeler à partir de la fonction main():
noeud *tete;
………
inserer (&tete);

28/03/2016 Langage C 29 / 69
Supprimer un noeud d’une liste
Quoi faire?

• Ici aussi, on doit supprimer un noeud


spécifique,
– Soit dans notre exemple, le noeud dont le code
est donné.
• Ici aussi, trois cas possibles:
– Supprimer le 1er noeud.
– Supprimer le dernier noeud.
– Supprimer un noeud du milieu.

28/03/2016 Langage C 31 / 69
void supprimer(noeud **tete)
{
int c1;
noeud *p, *q;

printf ("\nSupprimer pour le code: ");


scanf ("%d", &c1);

p = *tete;
if (p->code== c1)
/* Supprimer le 1er élément */
{
*tete= p->suiv;
free (p);
}

28/03/2016 Langage C 32 / 69
else
{
while ((p != NULL) && (p->code!= c1))
{
q = p;
p = p->suiv;
}

if (p == NULL) /* Elément non trouvé*/


printf ("\nEchec! Noeud non trouve");

else if (p->code == c1)


/* supprimer n’importe quel autre noeud*/
{
q->suiv = p->suiv;
free (p);
}
}
}

28/03/2016 Langage C 33 / 69
Liste FIFO: First In First Out

In Out

B A
C B A

Appelée aussi une FILE

28/03/2016 Langage C 34 / 69
Liste LIFO: Last In First Out
In Out

C B A B C

Appelée aussi
une PILE

28/03/2016 Langage C 35 / 69
Les piles
Opérations à effectuer sur une pile

void empiler(pile *s, int element);


/* Insérer un élément dans la pile */
int depiler(pile *s);
/* enlever un élément de la pile */
void creer (pile *s);
/* Créer une nouvelle pile*/
int estVide (pile *s);
/* Vérifier si la pile est vide*/
int estPlein(pile *s);
/* Vérifier si la pile est pleine */

28/03/2016 Langage C 36 / 69
Pile-suite

• Il y a deux méthodes pour implémenter une


Pile:
– En utilisant des tableaux
– En utilisant des listes chainées

28/03/2016 Langage C 37 / 69
Implémentation des Piles
Pile en utilisant des tableaux

EMPILER

top
top

28/03/2016 Langage C 39 / 69
Pile en utilisant des tableaux

DEPILER

top
top

28/03/2016 Langage C 40 / 69
Pile en utilisant liste chainée

EMPILER

top

28/03/2016 Langage C 41 / 69
Pile en utilisant liste chainée

DEPILER

top

28/03/2016 Langage C 42 / 69
Idée
• En utilisant des tableaux, on pourrait:
– Déclarer un tableau d’une taille fixe (qui détermine la taille maximale
de la pile).
– Maintenir une variable qui pointe toujours sur la tête de la pile.

• En utilisant une liste chainée, on pourrait:


– Simuler une pile à une liste chainée.
– Une variable pointeur top pointant sur le début de la liste.
– Le premier élément de la liste chainée est considérée comme la tête
de la pile.

28/03/2016 Langage C 43 / 69
Déclaration

#define MAXSIZE 100


struct lifo
struct lifo {
{ int val;
int st[MAXSIZE]; struct lifo *next;
int top; };
}; typedef struct lifo pile;
typedef struct lifo pile; pile *top;
pile s;

Tableau Liste chainée

28/03/2016 Langage C 44 / 69
Création de la Pile

void creer (pile *s) void creer (pile **top)


{ {
s->top = -1; *top = NULL;

/* s->top pointe sur /* top pointe sur


le dernier élément NULL, en indiquant une
empilé; initialisé à pile vide */
-1 */ }
}

Tableau Liste chainée

28/03/2016 Langage C 45 / 69
Fonction empiler
void empiler(pile *s, int element)
{
if (s->top == (MAXSIZE-1))
{
printf (“\n débordement ”);
exit(-1);
}
else
{
s->top ++;
s->st[s->top] = element;
}
}

Tableau

28/03/2016 Langage C 46 / 69
Fonction empiler
void empiler (pile **top, int element)
{
pile *new;
new = (pile*) malloc(sizeof(pile));
if (new == NULL)
{
printf (“\n Pile est pleine”);
exit(-1);
}
new->val = element;
new->next = *top;
*top = new;
}

Liste chainée
28/03/2016 Langage C 47 / 69
Dépiler un élément de la pile
int depiler(pile *s)
{
if (s->top == -1)
{
printf (“\n Rien a depiler”);
exit(-1);
}
else
{
return (s->st[s->top--]);
}
}

Tableau

28/03/2016 Langage C 48 / 69
int depiler(pile **top)
{
int t; // la valeur dépilée
pile *p;
if (*top == NULL)
{
printf (“\n pile vide”);
exit(-1);
}
else
{
t = (*top)->val;
p = *top;
*top = (*top)->next;
free (p);
return t;
}
}

Liste chainée
28/03/2016 Langage C 49 / 69
Fonction estVide

int estVide(pile *s) int estVide(pile *top)


{ {
if (s->top == -1) if (top == NULL)
return 1; return (1);
else else
return 0; return (0);
} }

Tableau Liste chainée

28/03/2016 Langage C 50 / 69
Fonction estPlein

int estPlein(pile *s) • N’est pas obligatoire aves les


{ listes chainées
if (s->top == MAXSIZE–1)) • Dans la fonction depiler(), on
return 1; peut vérifier la valeur
else retournée de malloc().
return 0; – Si -1, allors la mémoire ne
} pourra pas être allouée.

Liste chainée
Tableau

28/03/2016 Langage C 51 / 69
main():: tableau
#include <stdio.h> empiler(&A,30);
#define MAXSIZE 100 empiler(&B,100);
empiler(&B,5);
struct lifo
{ printf (“%d %d”,
int st[MAXSIZE]; depiler(&A), depiler(&B));
int top; empiler(&A, depiler(&B));
};
typedef struct lifo pile; if (estVide(&B))
printf (“\n B est vide”);
main()
}
{
pile A, B;
creer(&A); creer(&B);
empiler(&A,10);
empiler(&A,20);

28/03/2016 Langage C 52 / 69
main():: liste chainée
#include <stdio.h> empiler(&A,30);
struct lifo empiler(&B,100);
{ empiler(&B,5);
int val; printf (“%d %d”,
struct lifo *next; depiler(&A),
}; depiler(&B));
typedef struct lifo pile;
empiler(&A,depiler(&B));
main()
if (estVide(&B))
{
printf (“\n B est
pile A, B; vide”);
creer(&A); creer(&B); }
empiler(&A,10);
empiler(&A,20);

28/03/2016 Langage C 53 / 69
Les files: First-In-First-Out
Les opérations à effectuer sur une file

void enfiler (file *q, int element);


/* Insérer un élément dans une file */
int defiler (file *q);
/* Supprime un élément de la file */
file *creer();
/* Créer une nouvelle file */
int estVide (file *q);
/* Vérifie si la file est vide*/
int taille (file *q);
/* Retourne le nombre d’éléments dans la file */

28/03/2016 Langage C 54 / 69
Implémentation d’une file par liste
chainée
Idée de base
– Créer une liste chainée à laquelle les éléments
sont ajoutés d’un côté et supprimés de l’autre
côté.
– On aura besoin de deux pointeurs:
• Un pointant sur la tête de la liste (d’où les éléments
seront supprimés)
• Un autre pointant sur la queue de la liste (d’où les queue
éléments seront insérés).

Tête Suppression INSERTION


28/03/2016 Langage C 56 / 69
File: par liste chainée

Enfiler

Tête Queue

28/03/2016 Langage C 57 / 69
File: par liste chainée

DEFILER

Tête Queue

28/03/2016 Langage C 58 / 69
Exemple
• Soit une file de valeurs entières

struct noeud{
int val;
struct noeud *suiv; val *suiv
};
typedef struct noeud fifo;

typedef struct {
fifo *tete, *queue; *tete *queue
} file;

28/03/2016 Langage C 59 / 69
creer-estVide

void creer(file *q)


{
q->tete= q->queue=NULL;
}
int estVide(file *q)
{
if(q==NULL)
return 1;
else return 0;
}

28/03/2016 Langage C 60 / 69
Fonction enfiler
fifo *enfiler (file *q, int n) if(q->queue==NULL)
{ {
fifo *temp; q->queue=temp;
temp= (fifo *)malloc(sizeof(fifo)); q->tete= q->queue;
if (temp==NULL) }
{ else
printf("Erreur d’allocation \n"); {
return NULL; q->queue->suiv=temp;
} q->queue=temp;
temp->val=n; }
temp->suiv=NULL; return(q->queue);
}

28/03/2016 Langage C 61 / 69
Fonction defiler

void *defiler(file *q) else


{ {
int n; n=q->tete->val;
fifo *temp; temp=q->tete;
if(q->tete==NULL) q->tete= q->tete->suiv;
{ free(temp);
q->queue=NULL; if(q->tete==NULL)
printf("File est vide!!\n"); q->queue=NULL;
return(NULL); printf("La valeur defilee: %d",n);
} }
}

28/03/2016 Langage C 62 / 69
Implémentation avec Tableau

28/03/2016 Langage C 63 / 69
Implémentation avec Tableau

ENFILER DEFILER

zone de stockage effective du tableau de la file d'attente se réduit.

0 N

Tête Tête queue queue

Utilisation de l'indexation du tableau circulaire


28/03/2016 Langage C 64 / 69
Exemple

• Supposons une file de valeurs entières simulée par


un tableau.
• Les structures:
typedef struct {
#define MAX_SIZE 100 ELEMENT f_elem[MAX_SIZE];
typedef struct { int queue;
int val; int tete;
} ELEMENT; int plein,vide;
} file;

28/03/2016 Langage C 65 / 69
• Fonction initfile de création
void initfile(file *q)
{
q->queue= q->tete= 0;
q->plein=0; q->vide=1;
}

• Fonction estVide • Fonction estPlein


int estVide(file *q) int estPlein(file *q)
{ {
return(q->vide); return(q->plein);
} }

28/03/2016 Langage C 66 / 69
Fonction enfiler
void enfiler(file *q, ELEMENT ob)
{
if(estPlein(q)) { printf("File est pleine \n"); return; }

q->queue=(q->queue+1)%(MAX_SIZE);
q->f_elem[q->queue]=ob;

if(q->tete==q->queue) q->plein=1;
else q->plein=0;
q->vide=0;
}

28/03/2016 Langage C 67 / 69
Fonction defiler
ELEMENT defiler(file *q)
{
ELEMENT temp;
if(estVide(q)) { printf("File est vide\n"); return(temp); }
q->tete=(q->tete+1)%(MAX_SIZE);
temp=q->f_elem[q->tete];
if(q->queue==q->tete) q->vide=1; else q->vide=0;
q->plein=0;
return(temp);
}
28/03/2016 Langage C 68 / 69
FIN

28/03/2016 Langage C 69 / 69