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 15/02/2023 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 15/02/2023 Liste Chainée 4 Exemple de problème à résoudre PR M.EL FAR 15/02/2023 Liste Chainée 5 Résolution du problème Principe de base chaque élément peut avertir son suivant Tableaux ? Nombre d’éléments inconnu méthode à écarter Liste chainée ? Méthode adoptée pour les tailles dynamiques PR M.EL FAR 15/02/2023 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 15/02/2023 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 15/02/2023 Liste Chainée 8 Représentation en C PR M.EL FAR 15/02/2023 Liste Chainée 9 li -> premier li -> dernier 3 li liste li -> nbElt 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; // Un élément de la liste typedef struct element { Objet *data; struct element* suivant; } Element; // Le type liste typedef struct { Element *premier; Element *dernier; int nbElt; } Liste; Les principales opérations sur une liste chainée L’interface List.h #ifndef LISTE_H #define LISTE_H // definition de type boolean avec vrai et faux #define faux 0 #define vrai 1 typedef int boolean; typedef void Objet; // un élément de la liste typedef struct element { Objet*data; struct element *suivant; } Element; // le type Liste typedef struct { Element *premier; Element *dernier;//optionnel int nbElt; } Liste; //les opérations sur la liste void initListe(Liste *li); Liste* creerListe(); boolean listeVide(Liste *li); void insererEnTeteDeListe(Liste *li,Objet *o); void insererEnFinDeListe(Liste *li,Objet *o); Objet* extraireEnTeteDeListe (Liste* li); Objet* extraireApres(Liste* li,Element* precedent); Objet* extraireEnFinDeListe (Liste* li); // parcours de la liste void listerListe(Liste *li,void (*f) (Objet*)); 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 void initListe(Liste *li) { li->premier =NULL; li->dernier =NULL; li->nbElt=0; } // Création de la liste Liste* creerListe() { Liste* li; li=(Liste*)malooc(sizeof(Liste)); 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 List *li; li -> dernier 3 li -> nbElt Ajout en tête 3 4 li data 1 objet Data 2 data 3 null li -> premier = nouveau; nouveau -> suivant = li -> premier; li -> nbElt ++; Nouveau // Création du nouveau element nouveau -> suivant = li -> premier; void insererEnTeteDeListe (Liste* li, Objet* objet) {Element* nouveau; li -> premier = nouveau; nouveau=(Element*)malloc(sizeof(Element)); if (li->dernier == NULL) li -> dernier = nouveau; nouveau->data=objet; li -> nbElt ++; Ajout après un précédent 4 3 li précédent data 1 objet Nouveau void insererApres (Liste* li, Element* precedent, Objet* objet)) { if (precedent == NULL) { insererEnTeteDeListe (li, objet);} else { Element* nouveau = CreerElement(); nouveau->data=objet; Data 2 Précédent -> suivant data 3 precedent -> suivant = nouveau; nouveau -> suivant= precedent -> suivant; li -> nbElt ++; nouveau -> suivant= precedent -> suivant; precedent -> suivant = nouveau; if (precedent == li->dernier) li->dernier = nouveau; li->nbElt++; } } null Ajout en fin de liste li 3 4 data 1 Data 2 data 3 li-> dernier -> suivant = nouveau; objet Nouveau Void insererFinListe(Liste*li,Objet* objet) { Element* nouveau = CreerElement(); Else { li-> dernier -> suivant = nouveau; nouveau->data=objet; li->dernier = nouveau; li->nbElt++; if (li->premier == NULL) insereren TeteListe(Liste*li,Objet* objet); } null Supprimer un élément en tête de liste 3 2 li data 1 Extrait Objet* extraireEnTeteDeListe (Liste* li) { Element* extrait = li->premier; if (!listeVide(li)) { li -> premier = li -> premier -> suivant; if (li->premier==NULL) // Liste devenue vide li -> dernier=NULL; li->nbElt--;} return extrait != NULL ? extrait->reference : NULL; } Data 2 data 3 null Element* extrait = li -> premier; li -> premier = li -> premier -> suivant; Supprimer un élément en tête de liste Supprimer un élément en tête de liste 3 2 li data 1 Extrait Data 2 data 3 Liste* SupprimerTeteDeListe (Liste* li) { 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; } null Supprimer un élément en Fin de liste Supprimer un élément en Fin de liste li 3 2 data 1 Data 2 Liste* extraireFinDeListe (Liste* li) { data 3 NULL Element *e= li->premier; if (listeVide(li)) { return li;} If(li->nbElt==1) { free(li); li->nbElt--; return NULL;} while(e ->suiv ->suiv!=NULL) free(e ->suiv); li ->derneir=e; e ->suiv=NULL; li->nbElt--; return li;} e=e ->suiv; null Extrait Les listes doublement chainées Les listes doublement chainées Les listes doublement chainées 25 li -> premier li -> dernier li -> nbElt 3 li liste a b c Liste Doublement Chaînée cellule typedef void Objet; // un élément de la liste typedef struct element { Objet*data; struct element *suivant; struct element *precedent; } Element; // le type Liste typedef struct { Element *premier; Element *dernier;//optionnel int nbElt; } Liste; Initialisation et création d’une liste Doublement Chainée // Initialisation de la liste void initListe(Liste *li) { li->premier =NULL; li->dernier =NULL; li->nbElt=0; } // Création de la liste Liste* creerListe() { Liste* li; li=(Liste*)malooc(sizeof(Liste)); 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 // Création du nouveau element void insererEnTeteDeListe (Liste* li, Objet* objet) { Element* nouveau; nouveau=(Element*)malloc(sizeof(Element)); li -> premier = nouveau; li -> dernier = nouveau; } Else{ li -> premier ->prec=nouveau; nouveau -> suivant= li -> premier ; nouveau -> suiv=NULL; li -> premier=nouveau; nouveau -> prec=NULL nouveau->data=objet; if (li->dernier == NULL) { } li -> nbElt ++; } 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 ++; } Les listes doublement chainées insertion après un précédent void insererApres (Liste* li, Element* precedent, Objet* objet)) { if (precedent == NULL) insererEnTeteDeListe (li, objet); if (precedent == li->dernier) insererEnFinDeListe (li,objet); nouveau -> suivant= precedent -> suivant; precedent -> suivant = nouveau; nouveau -> prec=precedent; li->nbElt++; else{Element*nouveau= CreerElement(objet); } precedent -> suivant ->prec=nouveau; } Les listes doublement chainées Supprimer un élément void Supprimer (Liste* li, Objet* data)) 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