Vous êtes sur la page 1sur 98

Structures de données

Les listes chainées

1
Structures de données

Stocker les données


dans des
structures
2
Pour stocker …
Utilisation des tableaux
Il faut préciser la taille du tableau (n)
Exemple: n=5
0 1 2 3 4

Changer la taille du tableau si nécessaire?

0 1 2 3 4 5 6

3
• Recourt à des allocations dynamiques
de la mémoire avec la précision de la
dimension.
• En langage C, les tableaux offrent un
moyen statique de stockage

Existe –il un nouveau moyen dynamique


de stockage ?

4
Une nouvelle structure
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.

5
Listes chainées

Les listes chainées présentent un moyen


dynamique de stockage

6
Liste chainée
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.
Structure tableau :
T[1] T[2] T[3]

T A B C

Structure liste chaînée :

&A B C L’élément dans une LC :


A - Donnée utile.
&C NULL - Pointeur vers donnée suivante.
&B 7
Exemple de problème à résoudre
Comment servir tout les éléments?
Principe de base:
chaque élément peut avertir son suivant

On a un nombre d’éléments inconnu qui augmente


ou diminue suivant le besoin?
Méthode adoptée pour les tailles dynamiques:
Liste chaînée

Comment utiliser les listes chainées ?

8
Structuration des éléments
Pour que chaque élément arrive à avertir un
autre élément, il faut qu’il ait son adresse

Liaison entre les adresses


L’élément suivant

Dans une liste chainée, un élément ne voit


qu’un seul autre élément (son suivant)
Liste chainée
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.

A B
D
C

F
E
Liste chainée

Composition :
cellule

Donnée Donnée
Donnée

Donnée
Donnée

Lien

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. Il faut passer par les
précédents
1
Cette linéarité est virtuelle. 8
Liste chainée
Repérage des cellules :
Précédente
Tête

Donnée Donnée
Donnée

Donnée
Donnée
Suivante

Queue Comment parcourir une liste ?

1
9
Démarche

Servir le premier élément

Le premier élément averti son suivant (2ème élément)


Servir le deuxième élément
Le deuxième élément averti son suivant

….
Jusqu’à ce queue

ne reste aucun élément à servir

2
Représentation en C


Premier Dernier

élément élément

Les éléments de la liste


Représentation en C

?
Représentation en C

Information
s de
l’élément
Adresse du
suivant
Élément
Représentation en C

Information
1
s de
l’élément Donnée complexe
Adresse du
2
suivant
struct
element ?
{
type1 partie1
type2
?
partie2
Représentation en C

Information
1
s de
l’élément
Adresse du suivant 2
typdef struct element
{
int info; 1
struct element *suivant; 2
}
liste;
Algorithmes complexes

Il reste à structurer la
liste ?
Représentation en C

information

@suivant
information

@suivant
information

@suivant
… information

@suivant

@100 @200 @300 @700 Aucun


Début =
= Adresse Fin
Adresse de
début =
null
Représentation en C

information

@200
information

@300
information

@xxx
… information

@null

@100 @200 @300 @700


*p1 *p2 *p3 *pn
Adresse de
débu
t
Les principales opérations sur
une liste chainée

1. Insertion
2. Affichage
3. Suppression
Liste chainée

Ajouter/Suppression :
Cellule

Donnée Donnée
Donnée

Cellule Donnée
Donnée

Cellule
Exemple 1
Problème
Construire une liste chainée (L) qui contiendra
l’ensemble d’entier {7,5,13,9}
Algorithmes complexes

Le problème de
construction d’une liste
chainée se résume en un
problème d’insertion
Exemple 1
Représentation graphique de la liste chainée

Adresse du suivant

7 5 13 9

@200 @300 @xxx @null

@100 @200 @300 @700


*p1 *p2 *p3 *p4
Adresse de
*L l’élément courant

*L est un pointeur sur le premier


élément de la liste (*p1)
Exemple 1
Etape 1 : définition de la structure de donnée

typedef struct liste


{
int info;
struct liste *suivant;
}liste;
La liste est représentée par *L
liste *L;
//Au début, on peut mettre
L=NULL;
Insertion d’un nouveau élément dans la liste

Soit L une Liste

L
12 15 17 18 NULL

Nouveau Où l’insérer
Début

Milieu
3
Fin 6
Algorithmes complexes

Il faut toujours se
rappeler de L

3
7
Insertion d’un nouveau élément dans la liste
Au début de la liste

NULL

Créer nouveau
nouveau-
>suivant=L;
L=nouveau;
Insertion d’un nouveau élément dans la liste
À la fin de la liste

e1 e2 e3 e4 Nouveau NULL

Créer nouveau
Aller jusqu’à la fin de la liste (position=e4)
// à l’aide d’un autre pointeur *temp pour ne pas perdre L
position->suivant=nouveau;
nouveau->suivant=NULL; // obligatoire pour indiquer la fin de la liste
Le problème revient à se positionner à position 3
9
Insertion d’un nouveau élément dans la liste
En milieu

e1 e2 Nouveau e3 e4
NULL

Créer nouveau
Aller jusqu’à la position souhaitée
// à l’aide d’un autre pointeur *temp pour ne pas perdre L
//ici, position est entre e2 et e3
//ou autrement dit, entre e2 et e2->suivant
nouveau->suivant=e2->suivant;
// attention si e2 est NULL. Si c’est le cas, le
Exemple 1: Solution
Pour construire une liste chainée (L) qui contiendra
l’ensemble d’entier {7,5,13,9}
Exemple 1: Solution
Etape 1: Définir la structure de donnée

typedef struct element


{
int info;
struct element *suivant;
}element;
Exemple 1: Solution
Etape 2 : Insertion des éléments.

Chaque nouveau élément est inséré au début (tête


de la liste)

4
3
Exemple 1: Solution
int main()
{
element *L;
L=NULL;// L ne contient aucun élément
element *elt;
// élément 1
elt=(element*)malloc(sizeof(element));
elt->info=7;
elt->suivant=L;
L=elt;
// élément 2
elt=(element*)malloc(sizeof(element));
elt->info=5;
elt->suivant=L;
L=elt;
// élément 3
elt=(element*)malloc(sizeof(element));
elt->info=13;
elt-
>suivant=L;
L=elt;
// élément 4
elt=(element*)malloc(sizeof(element));
elt->info=9;
elt- 4
4
} >suivant=L;
Exemple 1 : Solution simple

Element *insertDebut(Element *L, int e)


{
Element *nouveau;
nouveau =(element*)malloc(sizeof(element));
nouveau ->info = e;
nouveau -> suivant = L;
return nouveau;
}
int main()
{
Element *L;
L=NULL;// L ne contient
aucun élément
L=insertDebut(L,7);
L=insertDebut(L,5);
L=insertDebut(L,13);
L=insertDebut(L,9);
}
Les principales opérations sur
une liste chainée

1. Insertion
2. Affichage
3. Suppression
Affichage des éléments de la liste
Il suffit de connaitre L …

e1 e2 e3 e4 NULL

Parcours à travers un autre pointeur qui reçoit L


Affichage des éléments de la liste
Exercice 1

Ecrit une fonction qui permet d’afficher le contenu d’une Liste L


Les principales opérations sur
une liste chainée

1. Insertion
2. Affichage
3. Suppression
Affichage des éléments de la liste
Il suffit de connaitre L …

e1 e2 e3 e4 NULL

Chercher l’élément à supprimer

À Il se trouve où ?
supprimer
Début

Milieu
Fin
Suppression d’un élément de la liste
Exercice 2

Ecrit une fonction qui permet de supprimer un élément de la liste.


Discuter tous les cas possibles
Traitement sur les listes chainées
Traitements relatifs à la structure :

Se positionner sur la première cellule.


Se positionner sur la dernière cellule.
Calculer la longueur d'une liste.
Reconnaître une liste vide.
Parcourir une liste.
Traitement sur les listes
chainées
Traitements relatifs aux données :

 Modification de données.
 Visualisation de l'information enregistrée dans une
cellule.
 Visualisation de toutes les informations
enregistrées.
 Suppression d'une cellule.
 Ajout d’une cellule.

Remarque : il est impossible d’accéder directement à la


position i dans une liste.
Les indices n’existe pas dans les listes chaînées
Manipulation d’une liste chainée
Les basiques :
Se positionner sur la première cellule :

PP Donnée Donnée Donnée Donnée

PS

cellule *PS
PS=PP
Manipulation d’une liste chainée
Les basiques :
Se positionner sur la dernière cellule :

PP Donnée Donnée Donnée Donnée


NULL
cellule * lastCel (cellule *pp)
{cellule *ps;
PS
ps=pp;
while(pssuivant!=NULL)
ps=pssuivant;

return ps;
}
Manipulation d’une liste chainée
Les basiques :
Une liste vide est une liste chaînée qui ne contient
aucun élément :
PP

int estVide (cellule *pp) {


return (pp== NULL ?1:0);
}
Ajout d’un élément :
L’opération d’ajout requiert:
 la création d’une nouvelle cellule;
 son insertion au reste de la liste :

 Tête de liste.
Reste de
 Fin de liste. Donnée
la liste

Cellule
Donnée

Cellule

5
9
Manipulation d’une liste chainée
Ajout en tête :

Créer un élément

Affecter une valeur

Le raccorder avec la liste

Exemple : créer une fonction qui renvoie


un pointeur vers l’élément
ajouté en tête de liste.
6
liste *ajoutEnTete(liste *l, int data){
liste *c;
c=(liste *) malloc(sizeof(list));
c->info=data; c->suivant=NULL;
if(c!=NULL)
c->suivant=l;
l=c;
return l;
}
Manipulation d’une liste chainée
Ajout en fin de liste :
Créer un élément liste *ps =(liste *)malloc(sizeof(liste));

Affecter une valeur ps->info=15;

Mettre l’adresse de l’élément ps->suivant=NULL;


suivant à NULL
if (pp!= NULL) {
faire pointer le dernier élément
de liste originale sur le nouvel ps=pp:
élément while (ps->suivant!
=NULL)
ps=ps->suivant:

}
Manipulation d’une liste chainée
Exercice :
Coder la fonction afficher(cellule* p) qui
permet de parcourir une liste et d’afficher son
contenu…
void afficher(cellule *p) {
cellule *curseur;

curseur = p;
while(curseur !=NULL ) {
printf("%d", curseur->info) ;
curseur=curseur->suivant;
}
}
Manipulation d’une liste chainée
Supprimer un élément de tête :
Il s'agit là de supprimer le premier élément de la liste.

Donnée Donnée

Donnée Donnée

Il faudra utiliser la fonction libérer(pointeur)


Manipulation d’une
Supprimer un élément de tête :
liste chainée

Si la liste n’est pas vide liste *supprimeTete( liste *pp) {


liste *ps;ps=pp;
Récupérer l’adresse du if (pp !=NULL ) {
deuxième élément. ps = l->suivant ;
free(l) ;
return (ps); }
Supprimer le premier else
élément return(NULL);

}
Manipulation d’une liste chainée
Supprimer un élément en fin de liste :

Donnée Donnée Donnée Donnée


Manipulation d’une liste chainée
Supprimer un élément en fin de liste :
liste * supprimerFin(liste *l) {
liste *c,*p; c=l;
Parcourir la liste if (l==NULL ) return NULL;
jusqu’au while(c->suivant!=NULL){
dernier p=c;
Rendre l’avant dernier c=c->suivant;}
élément dernier. p->suivant=NULL;
free(c);
return l;
Libérer le dernier }
élément

Renvoyer pointeur vers


premier élément
Manipulation d’une liste chainée
Recherche d’éléments :
Objectif : renvoyer l'adresse du premier élément trouvé
ayant une certaine valeur.

1 4 5 7

suivant
liste * recherche(int x, liste *l){

liste *c; c=l;


while(c!=NULL && c->info!=x){c=c->suivant;}
return c;
}
Soit la liste chaînée suivant avec Vi des entiers
a) Définir la structure de cette liste chainée
avec le mot clé en C (typedef) avec vi des
entiers

typedef struct cellule {


int nombre;
struct cellule*suivant;
}liste;
b) Ecrire la fonction : liste *AlloueCellule
qui alloue la mémoire à une cellule de la liste
liste * AlloueCellule() {
return (liste *) malloc(sizeof(list));
}
c) Ecrire la fonction : liste *CreerCellule(int x)
qui crée une cellule

liste * CreerCellule(int x) {
liste *c;
c=AlloueCellule();
If (c!=NULL){
c->info=x;
c->suivant=NULL;}
return c;
}
d) Ecrire la fonction : liste * InserEnTete(int x, liste *l)
qui insère une cellule à l’entête de la liste

liste * InsertEntete(int x, liste *l) {


liste *c;
c=CreeCellule(x);
if(c!=NULL)
c->suivant=l;
l=c;
return l;}
e)Ecrire une fonction : liste *InsertSuccessives(liste *l)
qui permet à l’utilisateur d’insérer à l’entête plusieurs cellules
et la répétition de l’insertion s’arrête si l’utilisateur tape la valeur 0

liste *InsertSuccessives( liste *l) {

liste *c; int x=1;

do{
printf("Donnez un entier 0 pour terminer"\n);
scanf("%d",&x);
if(x) {
c=InserEntete(x,l);
if (c!=NULL) {
c->suivant=l; l=c:}
else return l;
}
} while (x!=0); return c;
f) Ecrire la fonction itérative : liste * InsertOrd_Iter(int x, liste *l)
qui permet d’insérer une cellule en respectant l’ordre
décroissant des valeurs

liste * InsertOrd_Iter(int x, liste *l){


liste *c,*n,*p=NULL;
c=l;
while(c && x< c->info) {
p=c;
c=c->suivant;}
n=InserEntete(x,c);
if (n)
if (p) p->suivant=n;
else l=n;
else printf("mémoire insuffisante\n");
return l;
}
g) Ecrire la fonction récursive :
liste * InsertOrd_Recur(int x, liste *l)
qui permet d’insérer une cellule en respectant l’ordre
décroissant des valeurs

liste *InsertOrd_Recur(int x, liste *l){


if (l)
if (x<l->info) return InsertEntete(x,l):
else return (InsertEntete(l->info, InsertOrd_Recur(x,l->suivant));
else return InsertEntete(x,l);
}
h) Ecrire la fonction récursive : int longueur_Recur(list *l)
qui donne la longueur de la liste (nombre des cellules de la liste)

int longueur_Recur(list *l) {


if (l) return 1+ longueur_Recur(l->suivant);
else return 0;
}
i) Ecrire la fonction itérative : int longueur_Iter(list *l)
qui donne la longueur de la liste (nombre des cellules de la liste)

int longueur_Iter(list *l) {


int longueur=0;
while(l){
++longueur;
l=l->suivant;
}
return longueur;
}
j) Ecrire une fonction récursive : void affiche_Recur(liste *l)
qui affiche tous les cellules de la liste

void affiche_Recur(liste *l) {

if (l)
{ printf("%d\n",l->info);
affiche_Recur(l->suivant);}
}
k) Ecrire une fonction itérative : void affiche_Iter(liste *l)
qui affiche tous les cellules de la liste

void affiche_iter(liste(*l){
liste *c;
c=l;
while(c)
{ printf("%d\n",l->info);
c=c->suivant;
}
}
l) Ecrire la fonction récursive : void affiche_Inv_Recur(liste *l)
qui affiche en ordre inverse tous les cellules de la liste

void affiche_Inv_Recur(liste *l){


if (l){
affiche_Inv_Recur(l->suivant);
printf("%d\n",l->info);}
}
m) Ecrire la fonction itérative : liste * supprim_Un_Iter(int x, liste *l)
qui supprime un élément x de la liste

liste *supprim_Un_Iter(int x, liste *l){


liste *c; c=l;
liste *p;p=l;
if (l)
{
while (c!=NULL&& c->info!=x){
p=c;
c=c->suivant;}
if(c->info==x) // élément trouvé
p->suivant=p->suivant->suivant;
}
free(c);

return l;}
n) Ecrire la fonction récursive :
liste * supprim_Un_Recur(int x, liste *l)
qui supprime un élément x de la liste

liste * supprim_Un_Recur(int x, liste *l) {


if (l)
if(l->info==x) l=l->suivant;
else
l->suivant=supprim_Un_Recur(x,l->suivant);
return l;
}
o) Ecrire une fonction : liste * supprim_Tout_Recur(int x, liste *l)
qui supprime tous les cellules de liste

liste * supprim_Tout_Recur(int x, liste *l){


if(l)
if(l->info==x)
supprim_Tout_Recur(x,l->suivant);
else
l->suivant=supprim_Un_Recur(x,l->suivant);
return l;
}
p) Ecrire la fonction liste * libereliste(liste *l)
qui libère la mémoire

liste * libereliste(liste *l){


liste *p;
while (l){
p=l->suivant;
free(l);
l=p;
}
return l;
q) dans la fonction main() laissez l’utilisateur choisir entre les
différentes fonctions de l’exercice
main(){
liste *l; l=NULL; int choix x;
do{
printf("\t0 Quitter\n \t1 Inserer un entier\n \t2 Inserer Plusieurs\n");
printf("\t3 Affiche Rec\n \t4 Affiche Inverse\n \t5 Supprime x
Iterative\n");
printf("\t6 Quitter\n \t1 Inserer un entier\n \t2 Inserer Plusieurs\n");

scanf("%d",&choix);
switch (choix)
{
case 0 : break;
case1 : printf("donner l'entire:");scanf("%d",&x);
l=InserEntete(x,l);break;
case 2: l=Inser_Successives(l);break;

default: break;
}
}while choix;}
Définir la structure d'une Liste doublement chaînée

Une liste doublement chaînée (symétrique)est une


liste telle que chaque élément pointe sur l’élément
suivant et sur l’élément précédent
typedef struct cellule {
int info;
struct cellule *suivant
struct cellule *precedent
} liste
Allouer une cellule

list *allouer () {
return (liste*)malloc(sizeof(liste));
}
créer une cellule dans la liste

liste * creecellule(int x) {
liste *c;
c=allouer();
if (c!=NULL) {
c->suivant=NULL;
c->precedent=NULL;}
return c
insérer à l'entête

liste *inserent(int x, liste *l) {


liste *c;
c=creecellule(x);
if (c)
{
c->suivant=l;
if (l) l->precedent=c
}
return c;
}
Insérer après
liste *insereapres(int x,liste *l){
liste *c;
c=creecellule(x);
if (c )
if (l) {
c->precedent=l;
c->suivant=l->suivant;
if (l->suivant) l->suivant->precedent=c;
l->suivant=c;
}
return c;
}
Parcours la liste du premier au dernier

void affiche liste(*l){


liste *c;
c=l;
while(c)
{ printf("%d\n",l->info);
c=c->suivant;
}
}
Parcours la liste du dans l'ordre inverse
void afficheInverse liste(*l){
liste *c;
c=l;
while(c) c=c->suivant;
c= c->precedent;
while(c)
{ printf("%d\n",l->info);
c= c->precedent;
}

}
LES LISTES CIRCULAIRES

Une liste circulaire est une liste telle que le dernier élément
de la liste contient un pointeur sur le premier
1) Créer cette liste:
liste *creerListe(liste *last, int data)
2) Ajouter une cellule au début de la liste
liste *ajoutDebut(liste *last, int data)
3) Ajouter une cellule à la fin:
liste *ajouterFin(liste *last, int data)
4)Ajouter après une cellule de la liste:
liste *ajouterApres(liste *last, int data, int item)
5) une fonction qui parcourt la liste et affiche ses élément:
void traverse(liste *last)
5) Faire un menu qui utilise les 5 fonctions
#include <stdio.h>
#include <stdlib.h>

typedef struct Node


{
int data;
struct Node *suivant;
}liste;

liste *creerListe(liste *last, int data)


{

if (last != NULL)
return last;

liste *temp =(liste*)malloc(sizeof(liste));

temp -> data = data;


last = temp;

last -> suivant = last;

return last;
}
liste *ajoutDebut(liste *last, int data)
{
if (last == NULL)
return creerListe(last, data);

liste *temp =(liste *)malloc(sizeof(liste));

temp -> data = data;


temp -> suivant = last -> suivant;
last -> suivant = temp;

return last;
}
liste *ajouterFin(liste *last, int data)
{
if (last == NULL)
return creerListe(last, data);

liste *temp =(liste *)malloc(sizeof(liste));

temp -> data = data;


temp -> suivant = last -> suivant;
last -> suivant = temp;
last = temp;

return last;
}
liste *ajouterApres(liste *last, int data, int item)
{
if (last == NULL)
return NULL;
liste *temp, *p;
p = last -> suivant;
do
{
if (p ->data == item)
{
temp = (liste *)malloc(sizeof(liste));
temp -> data = data;
temp -> suivant = p -> suivant;
p -> suivant = temp;
if (p == last)
last = temp;
return last;
}
p = p -> suivant;
} while(p != last -> suivant);

printf(" n'est pas present dans la liste. \n");


return last;
}
void traverse(liste *last)
{
liste *p;

if (last == NULL)
{
printf("liste vide.\n");
return;
}

p = last -> suivant;

do
{
printf(" ..%i ...",p -> data) ;
p = p -> suivant;

}
while(p != last->suivant);

}
int main()
{
liste *last = NULL;

last = creerListe(last, 6);


last = ajoutDebut(last, 4);
last = ajoutDebut(last, 2);
last = ajouterFin(last, 8);
last = ajouterFin(last, 12);
last = ajouterApres(last, 10, 8);

traverse(last);

return 0;
}
Gérer une liste circulaire en utilisant deux pointeurs Tete et Queue

typedef struct Node

{
int info;
struct Node *suivant;
}node;

node *tete=NULL,*queue=NULL,*temp;

void creer();
void supprimer();
void afficher();
void creer()
{
node *newnode;
newnode=(node*)malloc(sizeof(node));
printf("\nEntrez la valeur : ");
scanf("%d",&newnode->info);
newnode->suivant=NULL;
if(queue==NULL)
tete=queue=newnode;
else
{
queue->suivant=newnode;
queue=newnode;
}

queue->suivant=tete;
}
void supprimer()
{
temp=tete;
if(tete==NULL)
printf("\n une erreur :");
else
{
if(tete==queue)
{
printf("\n%d",tete->info);
tete=queue=NULL;
}
else
{
printf("\n%d",tete->info);
tete=tete->suivant;
queue->suivant=tete;
}

temp->suivant=NULL;
free(temp);
}
}
void afficher()
{
temp=tete;
if(tete==NULL)
printf("\n vide");
else
{
printf("\n");
for(;temp!=queue;temp=temp->suivant)
printf("\n%d addresse=%u suivant=%u\t",temp->info,temp,temp->suivant);
printf("\n%d addresse=%u suivant=%u\t",temp->info,temp,temp->suivant);
}
}
int main()
{int chc;
do
{
printf("\nMenu\n\t 1 creer un element : ");
printf("\n\t 2 supprimer un element : ");
printf("\n\t 3 afficher la liste : ");
printf("\n\t 4 sortir : ");
printf("\n entrez votre choix : ");
scanf("%d",&chc);
switch(chc){
case 1:creer();break;
case 2:supprimer(); break;
case 3:afficher(); break;
case 4: return 1;
default: printf("\nInvalid choice :");}
}while(1);
return 0;
}

Vous aimerez peut-être aussi