Vous êtes sur la page 1sur 61

STRUCTURES DE DONNEES

Chapitre 2
Liste Chainée

Pr: Mohamed EL FAR


Liste Chainée
2

Objectifs recherchés :

 Allouer de l’espace mémoire en fonction du besoin.


 Simuler des phénomènes du monde réel :
 File d’attente dans un guichet.
 Urgences dans un hôpital.
 Dossiers empilés sur un bureau.

PR M.EL FAR 16/03/2020


Liste Chainée
3

Une liste chainée est un ensemble d’éléments qui


constituent ses nœuds,
Au contraire des tableaux, les éléments d’une liste
chainée ne sont pas placés côte à côte.

PR M.EL FAR 16/03/2020


Liste Chainée
4

Exemple de problème à résoudre

PR M.EL FAR 16/03/2020


Liste Chainée
5

Résolution du problème

Principe de base
chaque élément peut avertir son suivant
Tableaux ? Liste chainée ?
Nombre d’éléments inconnu Méthode adoptée pour les tailles dynamiques
méthode à écarter
PR M.EL FAR 16/03/2020
Liste Chainée
6

Définition :
Une structure de données composée d’éléments de même
type reliés de façon successive par des pointeurs..

PR M.EL FAR 16/03/2020


Liste Chainée
7

Composition :

Dans une liste chaînée les éléments sont rangés linéairement. Chaque élément est lié à son
successeur, il est donc impossible d'accéder directement à un élément quelconque de la liste.
Cette linéarité est virtuelle.
PR M.EL FAR 16/03/2020
Liste Chainée
8

Représentation en C

PR M.EL FAR 16/03/2020


Liste Chainée
9

li -> premier li -> dernier li -> nbElt

li 3
liste Liste chaînée
a b c

cellule
 une cellule est composée :
 d’un élément de la suite

 d’un lien vers la cellule suivante (pointeur)

 une liste chaînée est composé d’un ensemble de cellule


liste contient l’adresse de la première cellule; qui à son tour contient l’adresse de
la cellule suivante, ...
Liste Chainée
• Pour que le module de gestion des listes soit le plus général possible, il faut bien
séparer ce qui est spécifique des listes de ce qui est caractéristique des applications.

typedef void Objet; // Le type liste


// Un élément de la liste typedef struct {
typedef struct element { Element *premier;
Objet *data; Element *dernier;
struct element* suivant; int nbElt;
} Element; } Liste;
Les principales opérations sur une liste chainée
L’interface List.h

#ifndef LISTE_H //les opérations sur la liste


#define LISTE_H
// definition de type boolean avec vrai et faux void initListe(Liste *li);
#define faux 0 Liste* creerListe();
#define vrai 1
typedef int boolean; boolean listeVide(Liste *li);
typedef void Objet; void insererEnTeteDeListe(Liste *li,Objet *o);
// un élément de la liste
typedef struct element { void insererEnFinDeListe(Liste *li,Objet *o);
Objet*data; Objet* extraireEnTeteDeListe (Liste* li);
struct element *suivant;
} Element; Objet* extraireApres(Liste* li,Element* precedent);
// le type Liste Objet* extraireEnFinDeListe (Liste* li);
typedef struct {
Element *premier; // parcours de la liste
Element *dernier;//optionnel void listerListe(Liste *li,void (*f) (Objet*));
int nbElt;
} Liste; Objet *chercherUnObjet(Liste *li,Objet *o,
boolean (*f) (Objet *, Objet *));
Les principales opérations sur une
liste chainée
Initialisation et création d’une liste
// Initialisation de la liste // Création de la liste
void initListe(Liste *li) Liste* creerListe()
{ {
li->premier =NULL; Liste* li;
li->dernier =NULL; li=(Liste*)malooc(sizeof(Liste));
li->nbElt=0; initListe (li);
} return li;
}

•Premier pointe sur le premier élément de la liste


•Dernier pointe sur le dernier élément de la list
Ajout en tête

li -> premier li -> dernier li -> nbElt

li 3

List *li;
Ajout en tête
li 3
4

data Data data null


1 2 3

li -> premier = nouveau;


objet nouveau -> suivant = li -> premier;
li -> nbElt ++;
Nouveau

// Création du nouveau element nouveau -> suivant = li -> premier;


void insererEnTeteDeListe (Liste* li, Objet* objet) li -> premier = nouveau;
{Element* nouveau; if (li->dernier == NULL)
nouveau=(Element*)malloc(sizeof(Element)); li -> dernier = nouveau;
nouveau->data=objet; li -> nbElt ++;
Ajout après un précédent
li 4
3 précédent Précédent -> suivant

data Data data null


1 2 3

precedent -> suivant = nouveau;


objet nouveau -> suivant= precedent -> suivant;
li -> nbElt ++;
Nouveau
void insererApres (Liste* li, Element*
nouveau -> suivant= precedent -> suivant;
precedent, Objet* objet)) {
precedent -> suivant = nouveau;
if (precedent == NULL) {
if (precedent == li->dernier)
insererEnTeteDeListe (li, objet);}
li->dernier = nouveau;
else {
li->nbElt++;
Element* nouveau = CreerElement();
} }
nouveau->data=objet;
Ajout en fin de liste
li 3
4

data Data data null


1 2 3

li-> dernier -> suivant = nouveau; objet

Nouveau
Void insererFinListe(Liste*li,Objet* objet) { Else {
Element* nouveau = CreerElement(); li-> dernier -> suivant = nouveau;
nouveau->data=objet; li->dernier = nouveau;
if (li->premier == NULL) li->nbElt++;
insereren TeteListe(Liste*li,Objet* objet); }
Supprimer un élément en tête de liste

li 3
2

data Data data null


1 2 3

Extrait
Element* extrait = li -> premier;
Objet* extraireEnTeteDeListe (Liste* li) {
Element* extrait = li->premier; li -> premier = li -> premier ->
if (!listeVide(li)) { suivant;
li -> premier = li -> premier -> suivant;
if (li->premier==NULL) // Liste devenue vide
li -> dernier=NULL;
li->nbElt--;}
return extrait != NULL ? extrait->reference : NULL;
}
Supprimer un élément en tête de liste
Supprimer un élément en tête de liste
li 3
2

data Data data null


1 2 3

Liste* SupprimerTeteDeListe (Liste* li) {


Extrait
Element* e = li->premier;
if (listeVide(li)) { return li;}
if (!listeVide(li)) {
free(e);
li -> premier = li -> premier -> suivant;
if (li->premier==NULL) // Liste devenue vide
li -> dernier=NULL;
li->nbElt--;}
Return li; }
Supprimer un élément en Fin de liste
Supprimer un élément en Fin de liste
li 3
2

data Data data null


1 2 3

Liste* extraireFinDeListe (Liste* li) { NULL Extrait


Element *e= li->premier;
if (listeVide(li)) { return li;}
If(li->nbElt==1) {
free(li); li->nbElt--;
return NULL;}
while(e ->suiv ->suiv!=NULL) e=e ->suiv;
free(e ->suiv);
li ->derneir=e;
e ->suiv=NULL;
li->nbElt--;
return li;}
Les listes doublement chainées
Les listes doublement chainées
Les listes doublement chainées
25

li -> premier li -> dernier li -> nbElt

li 3
liste
Liste Doublement
a b c Chaînée

cellule
typedef void Objet; // le type Liste
// un élément de la liste typedef struct {
typedef struct element { Element *premier;
Objet*data; Element *dernier;//optionnel
struct element *suivant; int nbElt;
struct element *precedent; } Liste;
} Element;
Initialisation et création d’une liste
Doublement Chainée
// Initialisation de la liste // Création de la liste
void initListe(Liste *li) Liste* creerListe()
{ {
li->premier =NULL; Liste* li;
li->dernier =NULL; li=(Liste*)malooc(sizeof(Liste));
li->nbElt=0; initListe (li);
} return li;
}

•Premier pointe sur le premier élément de la liste


•Dernier pointe sur le dernier élément de la list
Les listes doublement chainées
Insertion au début
Les listes doublement chainées
Insertion au début

li -> premier = nouveau;


// Création du nouveau element
li -> dernier = nouveau; }
void insererEnTeteDeListe (Liste* li, Objet* objet) {
Else{
Element* nouveau;
li -> premier ->prec=nouveau;
nouveau=(Element*)malloc(sizeof(Element));
nouveau -> suivant= li -> premier ;
nouveau -> suiv=NULL;
li -> premier=nouveau;
nouveau -> prec=NULL
}
nouveau->data=objet;
li -> nbElt ++;
if (li->dernier == NULL) {
}
nouveau -> suivant =NULL;
Les listes doublement chainées
Insertion à la fin
Les listes doublement chainées
Insertion à la fin

// Création du nouveau element li -> premier = nouveau;


void insererEnFinDeListe (Liste* li, Objet* objet) { li -> dernier = nouveau; }
Element* nouveau; Else{
nouveau=(Element*)malloc(sizeof(Element)); li -> dernier ->suiv=nouveau;
nouveau -> suiv=NULL; nouveau -> prec= li -> dernier ;
nouveau -> prec=NULL li -> dernier=nouveau;
nouveau->data=objet; }
if (li->dernier == NULL) { li -> nbElt ++;
nouveau -> prec=NULL; }
Les listes doublement chainées
insertion après un précédent

void insererApres (Liste* li, Element*


precedent, Objet* objet)) { nouveau -> suivant= precedent -> suivant;
if (precedent == NULL)
precedent -> suivant = nouveau;
insererEnTeteDeListe (li, objet);
nouveau -> prec=precedent;
if (precedent == li->dernier)
li->nbElt++;
insererEnFinDeListe (li,objet);
else { Element* nouveau = CreerElement(); }
nouveau->data=objet; }
precedent -> suivant ->prec=nouveau;
Les listes doublement chainées
Supprimer un élément

void Supprimer (Liste* li, Objet* objet)) else { r->suiv->prec = r->prec;


{ Element* r= li->premier; int trouver=0; r->prec->suiv = r->suiv; }
while(r!=NULL && !trouver) { free(r);
if (r->data == data) { li->nbElt--; trouver = 1;
if (r->suiv == NULL) { }
li>dernier=r->prec; else {
li->dernier->suiv = NULL;} r = r->suiv;
else if (r->prec == NULL) { }
li->premier = r->suiv; }
li->premier->prec =NULL;} }
Les listes doublement chainées

FIN Chapitre 2
STRUCTURES DE DONNEES
Chapitre 2
Piles et Files
En utilisant les listes chainées
Pr: Mohamed EL FAR
Structures de données

1. Les piles

2
Les piles

Définition

Une pile (stack en anglais) est une structure dynamique


dans laquelle l'insertion ou la suppression d'un élément
s‘effectue toujours à partir de la même extrémité de
cette structure.
Cette extrémité est appelée le sommet de la pile.

3
Les piles
Principe de LIFO
Une pile permet de modéliser un système régi
par le mécanisme « dernier arrivé premier
sorti » : (Lifo : last in, first out).
•L'action pour ajouter un nouvel élément au sommet
de la pile s'appelle Empiler
•L’action pour retirer l‘élément situé au sommet de
la pile s'appelle Dépiler

4
Les application des piles
Utilisation
De nombreuse applications s'appuient sur l'utilisation d'une pile, on peut
citer :
• Dans 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 ».
•L‘évaluation des expressions mathématiques en notation post-fixée (ou
polonaise inverse) utilise une pile.
•La fonction « Annuler la frappe » (en anglais « Undo ») d'un
traitement de texte mémorise les modifications apportées au texte
dans une pile.
• Vérification de parenthèse d'une chaine de caractères ;
• La récursivité (une fonction qui fait appel a elle même) ;
• etc.…
5
Les application des piles

Exemple de Pile (1)


Ajouter dans cet ordre A B C D E F

Pile
6
Les application des piles

Exemple de Pile (2)

A
Pile
7
Les application des piles
8
Implémentation d’une pile
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

Représentation chaînée (par pointeurs) :


Les éléments de la pile sont chaînés entre eux
Un pointeur sur le premier élément désigne la pile et
représente le sommet de cette pile
Une pile vide est représentée par le pointeur NULL

1
Implémentation d’une pile

On peut implémenter une pile à l’aide de la même structuration qu’une liste chainée

@
*P
e @ e @ e @ e NUL
1 2 3 4 L

1
Implémentation d’une pile
Pile chaînée

Pile
Sommet de la pile
pointée par p

10 20

p Pointeur
NULL
Cellule contenant la
valeur 5
50
Pointeur sur cellule
suivante
Pile chaînée
 Les éléments (nœuds) de la pile sont chaînés entre eux

nœud1 nœud2 nœudn


Debut 10 & du svt 66 & du svt 77 & du svt NULL
Sommet

//type clé
//type Pile
typedef int cle; typedef struct {
//type nœud Nœud* premier;
typedef struct noeud{ Nœud* dernier;
cle Valeur; Int nbr;
struct nœud *suivant; }Pile
} Noeud;
Spécification d’une pile chaînée

Voici les primitives communément utilisées :*


Pile* CreerPile(); //la pile créée est vide
boolean est_vide(Pile* p);//teste si la pile est vide ou non
void empiler(Pile* p,Cle v); //ajoute un élément dans la pile
cle depiler(Pile* p);//enlève un élément situé au sommet de la pile
void afficher_pile(Pile* p);//affiche les éléments de la pile
int sommet(Pile *p);//renvoie l‘élément sommet de la pile P ;

Sommet

Debut Cle1 & du svt Cle2 & du svt Clen & du svt NULL

13
Réalisation d’une pile chaînée (1)

//empile un élément dans la pile


//initialisation de la pile
void empiler (Pile* p,cle v)
Pile* CreerPile()
{
{
insererEnTete (p, v);
Pile* p=(Pile*) malloc (sizeof (Pile));
}
p->premier =NULL;
int sommet(Pile *p)
p->dernier =NULL;
{ if(est_vide(p)
p->nbr=0;
printf("pile vide!");
Return p
else
}
return p->premier->val; Debut NULL
//teste si la pile est vide
}
boolean est_vide(Pile* p)
{ return (p->premier == NULL); } debut->suivant
Debut Cle1 & du svt … & du svt NULL

v & du svt
nœud N
Réalisation d’une pile chaînée (2)

//depiler une valeur de la pile


cle depiler (Pile* p)
{ cle x;
x=extraireEnTete (p);
return x;
} Sommet
Debut Cle1 & du svt Cle2 & du svt Clen & du svt NULL
N=debut->suivant
Sommet
Debut Cle1 & du svt Cle2 & du svt Clen & du svt NULL
N->suivant
//affiche les éléments de la pile
void afficher_pile(Pile* p)
{ int i;
if (est_vide(p)) printf("\npile vide");
else { Nœud* N=p->premier;
printf("debut->");
while(N!=NULL)
{ printf("%d->",N->valeur); N=N->suivant; }
printf("fin\n");
}
} 12
2. Les files

2
Les Files

Définition
Une File (queue en anglais ) est une structure de
données dans laquelle l'insertion se fait à la fin et la
suppression d'un élément s'effectue à partir de début
de cette structure.
Le fonctionnement ressemble à une file d'attente :
les premières personnes arrivées, se sont les
premières personnes à servir.

2
Les files

Principe de FIFO
Une file permet de modéliser un système régi par le
mécanisme "premier arrivé premier sorti" ; on dit
souvent FIFO (First in, First out)
•L'action pour ajouter un nouvel élément s'appelle
Enfiler

•L'action pour retirer l‘élément situe au début de la File


s'appelle Défiler
Les application des files
2
3
Les application des files

Exemple de File (1) A B C D E F

Ajouter dans cet ordre

File
Les application des files

Exemple de File (2)


A B C D E F

File
Les application des files

Utilisation
• En général, on utilise des files pour mémoriser temporairement des
transactions qui doivent attendre pour être traitées ;
•Les serveurs d'impression, qui doivent traiter les requêtes dans l'ordre dans
lequel elles arrivent, et les insèrent dans une file d'attente ( ou une queue) ;
•Certains moteurs multitâches, dans un système d'exploitation, qui doivent
accorder du temps-machine a chaque tâche, sans en privilégier aucune ;
•Un algorithme de parcours en largeur utilise une file pour mémoriserles nœuds
visités ;
•On utilise aussi des files pour créer toutes sortes de mémoires tampons (en
anglais buffers).
• etc.…
Les application des files

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
Représentation chaînée (par pointeurs) :
Les éléments de la file sont chaînés entre eux
Un pointeur sur le premier élément désigne la file et
représente la tête de cette file
Un pointeur sur le dernier élément représente la queue de
file
Une file vide est représentée par le pointeur NULL
Implémentation d’une file

On peut implémenter une file à l’aide de la même structuration qu’une


liste chainée
@
*premier

@ e @ e @ e @ e NUL
1 2 3 4 L
*dernier

Et on mémorise le premier et le dernierélément


Les application des files
File
File chaînée
Tête de la file pointée
par tete

Pointeur sur cellule


suivante

10 20

tete
Pointeur
queue NULL

50

Cellule contenant la
valeur 30 Queue de file pointée
par queue
3
Implémentation d’une File

Syntaxe pour définir la structure de la File


//Définir la structure cellule
typedef struct Element
{
int info ; //le champ info peut avoir n'importe quel type
struct Element *suiv ; //pointeur contenant l'adresse de l’élément suivant
} Element;

//Définir la structure File


typedef struct
{
Element* premier;
Element* dernier;
Int nbr;
} File;
Opérations sur une file

Voici les primitives communément utilisées :


File* CreerFile(); //la file créée est vide
boolean est_vide(File* f);//teste si la file est vide ou non
void enfiler(File* f,info v); //ajoute un élément dans la file
info defiler(File* f);// supprime de la file F le premier élément
void afficher_file(File* f);//affiche les éléments de la file
Implémentation d’une file

File * CreerFile() //defiler une valeur de la file


{ info defiler (File* f)
File* f=(File *) malloc (sizeof (File)); {
f ->premier =NULL; info x;
f ->dernier =NULL; x=extraireEnTete (f);
f ->nbr=0;
Return f; return x;
} }

void emfiler (File* f,info v)


{
insererEnFin (f, v);
}

Vous aimerez peut-être aussi