LES STRUCTURES DE
DONNÉES DYNAMIQUES
anis.bennacib@gmail.com A.U 2023-2024
INTRODUCTION
Structure de données
o Une manière particulière de stocker et d'organiser les données dans un support afin qu'elles
puissent être utilisées efficacement.
o Il s'agit d'un groupe d'éléments de données regroupés sous un même nom.
o Il est également appelé "Type de données abstrait (ADT)"
Dans quel but?
Pour plus d'efficacité et la facilité de :
o Stockage des données
o Récupération de données
o Manipulation de données
Problème de conception :
Le défi est de sélectionner la structure de données la plus appropriée pour le problème
LISTE DES STRUCTURES DE DONNÉES(DE BASE)
Les tableaux(Arrays) Listes chaînées (Linked Lists)
Les Files(Queues) Les Arbres(Trees)
Les Piles(Stacks)
CLASSIFICATION DES STRUCTURES DE DONNÉES
Basé sur l’existence:
Structures de données physiques
Peut être créé indépendamment :
• Tableau
• Liste chaînée
Structures de données logiques
Ne peut pas être créé indépendamment
• Pile
• Files
• Les Arbres
• Les graphes
CLASSIFICATION DES STRUCTURES DE DONNÉES
Basé sur l’allocation de mémoire :
Structures de données statiques (ou de taille fixe)
Tels que les tableaux
Structures de données dynamiques (modifier la taille selon les besoins)
Telles que les listes chaînées
CLASSIFICATION DES STRUCTURES DE DONNÉES
Basé sur la représentation:
Structures de données linéaires
• Les tableaux
• Les listes chaînées
• Les piles
• Les files
Structures de données non linéaires
• Les arbres
• Les graphes
LES OPÉRATIONS DE BASE SUR LES STRUCTURES DE DONNÉES
Parcourir tous les éléments
Rechercher un élément ou son emplacement
Insérer un élément(au début, à la fin, avant ou après un élément donné…),
Supprimer un élément
Trier les éléments(croissant ou décroissant)
Fusionner les éléments de deux (ou plus) structures de données
LES TABLEAUX (ADT)
LES TABLEAUX ADT
Sauvegarde de donnée
Collection séquentielle des éléments de même type et de nombre fixe.
Opération
Créer(Allocation dynamique)
Remplir un tableau
Afficher les éléments d'un tableau
Insérer un élément
Recherche d'un élément
Supprimer un élément
Fusionner deux tableaux(ou plus)
LES LISTES CHAÎNÉES
SIMPLES - DOUBLES - CIRCULAIRES
LISTES CHAÎNÉES (POURQUOI?)
Les tableaux peuvent être utilisés pour stocker des données linéaires de types similaires, mais les
tableaux présentent les limitations suivantes.
La taille des tableaux est fixe.
L’insertion d’un nouvel élément dans un tableau d’éléments est coûteuse.
La suppression est également coûteuse avec les tableaux jusqu’à ce que des techniques spéciales
ne soient utilisées.
Avantages
Taille dynamique
Simplicité d’insertion/suppression
Inconvénients
L’accès aléatoire n’est pas autorisé. Nous devons accéder aux éléments séquentiellement à partir du
premier nœud.
Un espace mémoire supplémentaire pour un pointeur est requis pour chaque élément de la liste.
LES LISTES CHAÎNÉES SIMPLES
I. LISTES CHAÎNÉES SIMPLES
Définition
Une liste chaînée est une structure dynamique formée d’éléments(nœuds) de même
types reliés par des liens(des pointeurs). Les nœuds de la liste sont éparpillés dans
la mémoire.
Tête
Chaque nœud de la liste est constitué de deux parties :
NULL
un champ qui contient L'adresse
un champ de données de l'élément suivant(Pointeur)
I. LISTES CHAÎNÉES SIMPLES
Remarques
Tête
NULL
Une liste chainée est caractérisée par l’adresse de son premier élément(Le pointeur Tête).
Le dernier élément d’une liste chainée simple contient un pointeur vers NULL.
Une liste chaînée d'un élément contient un pointeur(tête) vers l'unique nœud de liste qui
pointe vers NULL.
Le dernier élément existant, son champ suivant vaut NULL.
Une liste vide ne contient pas de nœud, le pointeur Tête pointe donc vers la valeur NULL.
DÉCLARATION
I. LISTES CHAÎNÉES SIMPLES
Déclaration En algorithme
TYPE
Nom_noeud= Enregistrement
donnee : Type_donnee
suivant : Pointeur sur Nom_noeud
FinNom_noeud
Nom_Liste = Pointeur sur Nom_noeud
NB.
• La partie "donnée" de nœud peut être de type prédéfini ou définie par l'utilisateur.
• Le pointeur suivant pointe sur l'enregistrement dont il fait partie de ses champs, il s'agit d'une déclaration
récursive.
I. LISTES CHAÎNÉES SIMPLES
Déclaration En C
//Définition de la structure Nom_Noeud
typedef struct nom_Noeud
{
type_donnee data;
struct nom_noeud* next;
} Nom_Noeud;
//Définition de la liste chaînée
typedef Nom_Noeud * Nom_Liste;
NB.
Pour faciliter la manipulation de la liste, on définit le nouveau type Nom_Liste comme étant un
pointeur sur un Nom_Noeud.
Créer une Liste chaînée simple(LSC) vide.
Tester si une LCS est vide
Ajouter un élément à une LSC(au début, à la fin et
avant ou après un élément donné)
Parcourir une LCS / Affichage
Compter le nombre d'éléments d'une LCS
Supprimer un élément d'une LSC
OPERATIONS SUR LES
Mettre à jour les données d'un élément d'une LSC
LISTES CHAÎNÉES
Chercher un élément dans une LSC
SIMPLES
Trier les éléments d'une LSC(croissant et
décroissant)
Fusionner deux LSC,
Etc,
I. LISTES CHAÎNÉES SIMPLES
Soit les déclarations suivantes :
Déclaration En algorithme Déclaration En C
//Définition de la structure Nom_Noeud
TYPE
typedef struct noeud
Noeud = Enregistrement {
donnee : entier int data;
suivant : Pointeur sur Noeud struct noeud* next;
} Noeud;
FinNoeud
//Définition de la liste chaînée
PNoeud = Pointeur sur Noeud typedef Noeud* PNoeud;
NB.
Dans tout ce qui suit, nous supposons qu'une liste chaînée simple contenant les identifiants des membres d'un
club a été créé et qu'on dispose de la variable pointeur "Tete_Liste" qui pointe sur le premier élément de la
liste.
CRÉATION D'UNE LISTE CHAÎNÉE SIMPLE VIDE
(INITIALISATION DE LA LISTE)
TESTER SI UNE LISTE CHAÎNÉE SIMPLE EST
VIDE
I. LISTES CHAÎNÉES SIMPLES
Création d'une liste chaînée simple vide (initialisation de la liste)
Algorithme de la procédure Creer_Liste
Procédure Créer_Liste(var Tete_Liste : PNoeud)
Début
Tete_Liste ⃪ NULL
Fin
Implémentation de la procédure Creer_Liste en C
PNoeud Creer_Liste(void)
{
int main()
return NULL;
{
}
PNoeud Tete_Liste = Creer_liste();
}
I. LISTES CHAÎNÉES SIMPLES
Tester si une liste chaînée simple est vide
Algorithme de la fonction estVide
Fonction estVide(Tete_Liste : PNoeud):booléen
Début
Retourner Tete_Liste=NULL
Fin
Implémentation de la procédure Creer_Liste en C
int estVide(PNoeud Tete_Liste)
{
return Tete_Lsite==NULL;
}
AJOUTER UN ÉLÉMENT (NOEUD)
AU DÉBUT(TÊTE) D'UNE LISTE
I. LISTES CHAÎNÉES SIMPLES
Ajouter un élément(nœud) au début d'une liste(en tête)
1er cas : La liste est vide 2ème cas : La liste n'est pas vide
221 Tête 201
Tête NULL
NULL
Tête
201
221 201
NULL
NULL
Tête
Tête 201 221 201
NULL NULL
I. LISTES CHAÎNÉES SIMPLES
Ajouter un élément(nœud) au début d'une liste(en tête)
Algorithme de la procédure Ajouter_Debut
Procédure Ajouter_Début(var Tete_Liste : PNoeud; id : entier)
Var
nouveau : PNoeud
Début
nouveau ⃪ Allouer (taille (Noeud))
*nouveau.donnee ⃪ id
*nouveau.suivant ⃪ Tete_Liste
Tete_Liste ⃪ nouveau
Fin
I. LISTES CHAÎNÉES SIMPLES
Ajouter un élément(nœud) au début d'une liste(en tête)
Implémentation en C
PNoeud Ajouter_Debut(PNoeud Tete_Liste; int id)
{
PNoeud nouveau = (PNoeud)malloc (sizeof (Noeud));
if(!nouveau)
{
printf("erreur d'allocation ! ");
}
nouveau->donnee = id;
nouveau->suivant = Tete_Liste;
Tete_Liste = nouveau; //Tete_Liste = nouveau;
Return Tete_Liste ;
}
Remarque :
Ne pas confondre l’utilisation du point "." et l’utilisation de la flèche "->" pour accéder
aux champs d’une structure. On utilise le point pour une variable de type structure, et
une flèche pour une variable de type pointeur sur structure.
La fonction renvoie la nouvelle adresse de la tête de liste.
Avec des insertions en tête de liste, la liste obtenue est classée à l’envers, le dernier
élément saisi étant le premier élément de la liste. Pour obtenir les éléments à l’endroit,
il faudrait faire les insertions en queue de liste .
PARCOURIR UNE LISTE CHAÎNÉE
I. LISTES CHAÎNÉES SIMPLES
Parcourir une liste chaînée simple
L’idée du parcours de liste chaînée est de :
Prendre un pointeur auxiliaire p.
On fait pointer p sur la première cellule, puis le pointeur p passe à la cellule suivante (par une
affectation p=p->suivant), etc.
Le parcours s’arrête lorsque p vaut le suivant de la dernière cellule, c’est-à-dire lorsque p vaut NULL
Tête
NULL
I. LISTES CHAÎNÉES SIMPLES
Parcourir une liste chaînée simple(dans l'ordre)
Algorithme de la procédure Afficher_LSC
Procédure Afficher_LSC(Tete_Liste : PNoeud)
Var
P : PNoeud
Début
Si estVide(Tete_Liste) Alors
Ecrire("Liste vide")
Sinon
P ⃪ Tete_Liste Répéter
TantQue(P≠NULL)faire Ecrire(*P.donnee)
Ecrire(*P.donnee) Ou bien P ⃪ *P.suivant
P ⃪ *P.suivant Jusqu'à (P = NULL)
finTantQue
finSi
Fin
AJOUTER UN ÉLÉMENT (NOEUD)
EN FIN(QUEUE) D'UNE LISTE
I. LISTES CHAÎNÉES SIMPLES
Ajouter un élément(nœud) en fin de liste (en queue)
L’insertion d’un élément en queue de liste est un peu plus compliquée que l’insertion en tête de
liste.
Elle nécessite un parcours de la liste pour rechercher l’adresse du dernier élément.
La condition d’arrêt est lorsque p->suivant égale à NULL parce que nous cherchons l’adresse
de dernier élément.
C’est un cas différent du parcours de liste chaînée, où il faut traiter le dernier élément comme
les autres.(Affichage)
L’insertion en queue de liste permet de saisir une liste chaînée à l’endroit.
I. LISTES CHAÎNÉES SIMPLES
Ajouter un élément(nœud) en fin de liste (en queue)
Tête
NULL
301
I. LISTES CHAÎNÉES SIMPLES
Ajouter un élément(nœud) en fin de liste (en queue)
Tête
NULL
301
Ajouter un élément(nœud) en fin de liste (en queue)
Algorithme de la procédure Ajouter_Fin
Procédure Ajouter_Fin(var Tete_Liste : PNoeud; tel : entier)
Var
P, nouveau : PNoeud
Début
nouveau ⃪ Allouer (taille (Noeud))
*nouveau.donnee ⃪ tel
*nouveau.suivant ⃪ NULL
Si estVide(Tete_Liste) Alors
Tete_Liste ⃪ nouveau
Sinon
P ⃪ Tete_Liste
TantQue(*P.suivant≠NULL)faire
P ⃪ *P.suivant
finTantQue
*P.suivant ⃪ nouveau
finSi
Fin
Compléments :
La création d’une liste chaînée par insertions en queue prend un nombre d’opérations
quadratique (O(n2)) par rapport au nombre de nœuds. On peut éviter cela et écrire un
algorithme linéaire (O(n)) en maintenant tout au long de l’algorithme un pointeur sur le
dernier nœud, sans le rechercher à chaque fois par un parcours de liste.
(voir exemple_complet_lsc02.C)
INSÉRER UN ÉLÉMENT (NOEUD) À
UNE POSITION SELON UN CRITÈRE
EXERCICE D’APPLICATION
Écrire un module qui prend en paramètre une liste chaînée supposée triée
dans l'ordre croissant, un entier (val) à insérer dans la liste de façon que les
valeurs entières de liste restent classées en ordre croissant.
I. LISTES CHAÎNÉES SIMPLES
Insérer un élément dans une liste triée
1er cas : Si la liste est vide, le nouveau élément à insérer devient le premier
Tête
10
nouveau NULL
2ème cas : La liste n'est pas vide mais il faut insérer au début parce que la nouvelle valeur est inférieure à
celle du premier élément : si nouveau->val < premier->val
Tête
Tête
10 20
10 20
nouveau NULL nouveau
NULL
I. LISTES CHAÎNÉES SIMPLES
Insérer un élément(Noeud) dans une liste triée
3ème cas : Dernier cas, l'élément est à insérer quelque part dans la liste.
Pour ce faire il faut chercher la bonne place et conserver l'adresse de l'élément qui précède.
Tête
10 30 60 70 140 200
50 NULL
nouveau
I. LISTES CHAÎNÉES SIMPLES
Insérer un élément(Noeud) dans une liste triée
3ème cas : Dernier cas, l'élément est à insérer quelque part dans la liste.
Pour ce faire il faut chercher la bonne place et conserver l'adresse de l'élément qui précède.
Tête
10 30 60 70 140 200
50 NULL
nouveau
Insérer un élément(Noeud) dans une liste triée
Algorithme de la procédure Insérer_Asc
Procédure Insérer_Asc(var Tete_Liste : PNoeud; val : entier)
Var
nouveau, courant, precedent : PNoeud
Début
nouveau ⃪ Allouer (taille (Noeud))
*nouveau.donnee ⃪ val
Si (estVide(Tete_Liste) ou *nouveau.donnee≤*Tete_Liste.donnee) Alors
*nouveau.suivant ⃪ Tete_Liste
Tete_Liste ⃪ nouveau
Sinon
courant ⃪ Tete_Liste
precedent ⃪ Tete_Liste
TantQue(courant≠NULL et *nouveau.donnee>*courant.donnee)faire
precedent ⃪ courant
courant ⃪ *courant.suivant
finTantQue
*nouveau.suivant ⃪ courant
*precedent.suivant ⃪ nouveau
finSi
Fin
DÉTRUIRE UNE LISTE CHAÎNÉE
(LIBÉRATION MÉMOIRE)
I. LISTES CHAÎNÉES SIMPLES
Détruire une liste chaînée simple.
Pour libérer la mémoire d’une liste chaînée, il faut détruire chacun des éléments(Nœud)
Tête
10 20 70
NULL
Temp
I. LISTES CHAÎNÉES SIMPLES
Détruire un liste chaînée simple.
Pour libérer la mémoire d’une liste chaînée, il faut détruire chacun des éléments(Nœud)
Tête
10 20 70
NULL
Temp
I. LISTES CHAÎNÉES SIMPLES
Détruire un liste chaînée simple.
Pour libérer la mémoire d’une liste chaînée, il faut détruire chacun des éléments(Nœud)
Tête
10 20 70
NULL
Temp
I. LISTES CHAÎNÉES SIMPLES
Détruire un liste chaînée simple.
Pour libérer la mémoire d’une liste chaînée, il faut détruire chacun des éléments(Nœud)
Tête
10 20 70
NULL
Temp
I. LISTES CHAÎNÉES SIMPLES
Détruire un liste chaînée simple.
Pour libérer la mémoire d’une liste chaînée, il faut détruire chacun des éléments(Nœud)
Tête
10 20 70
NULL
Temp
I. LISTES CHAÎNÉES SIMPLES
Détruire un liste chaînée simple.
Pour libérer la mémoire d’une liste chaînée, il faut détruire chacun des éléments(Nœud)
Tête
10 20 70
NULL
Temp
I. LISTES CHAÎNÉES SIMPLES
Détruire un liste chaînée simple.
Pour libérer la mémoire d’une liste chaînée, il faut détruire chacun des éléments(Nœud)
Tête
NULL
I. LISTES CHAÎNÉES SIMPLES
Détruire un liste chaînée simple.
Algorithme de la procédure Detruire_LSC
Procédure Detruire_LSC (Tete_Liste : PNoeud)
Var
temp : PNoeud
Début
temp ⃪ Tete_Liste
Si estVide(Tete_Liste) Alors
Ecrire("Liste vide")
Sinon
TantQue(Tete_Liste ≠NULL)faire
temp ⃪ Tete_Liste
Tete_Liste ⃪ *Tete_Liste.suivant
Libérer(temp)
finTantQue
finSi
Fin
SUPPRESSION D'UN ÉLÉMENT EN
TÊTE DE LISTE
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément en tête de la liste
La suppression du premier élément suppose de bien actualiser la valeur du pointeur premier qui
indique toujours le début de la liste
Tête
10 20 70
NULL
Temp
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément en tête de la liste
La suppression du premier élément suppose de bien actualiser la valeur du pointeur premier qui
indique toujours le début de la liste
Tête
10 20 70
NULL
Temp
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément en tête de la liste
La suppression du premier élément suppose de bien actualiser la valeur du pointeur premier qui
indique toujours le début de la liste
Tête
20 70
NULL
Temp
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément en tête de la liste
Algorithme de la procédure Supprimer_Premier
Procédure Supprimer_Premier(Tete_Liste : PNoeud)
Var
temp : PNoeud
Début
temp ⃪ Tete_Liste
Si estVide(Tete_Liste) Alors
Ecrire("Liste vide")
Sinon
temp ⃪ Tete_Liste
Tete_Liste ⃪ *Tete_Liste.suivant
Libérer(temp)
finSi
Fin
SUPPRESSION D'UN ÉLÉMENT EN
FIN DE LISTE
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément en fin de la liste
La suppression à la fin suppose de se positionner sur l'avant dernier élément puis de supprimer
le suivant et de mettre suivant à NULL. Il faut que la liste ne soit pas vide et traiter le cas ou il n'y a
qu'un seul élément dans la liste, le premier
1er cas : Si la liste composée d'un seul élément
Tête
10
NULL
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément en fin de la liste
La suppression à la fin suppose de se positionner sur l'avant dernier élément puis de supprimer
le suivant et de mettre suivant à NULL. Il faut que la liste ne soit pas vide et traiter le cas ou il n'y a
qu'un seul élément dans la liste, le premier
1er cas : Si la liste composée d'un seul élément
Tête
NULL
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément en fin de la liste
La suppression à la fin suppose de se positionner sur l'avant dernier élément puis de supprimer
le suivant et de mettre suivant à NULL. Il faut que la liste ne soit pas vide et traiter le cas ou il n'y a
qu'un seul élément dans la liste, le premier
*(*P.suivant).suivant ≠ NULL
Tête
10 20 70
NULL
P
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément en fin de la liste
La suppression à la fin suppose de se positionner sur l'avant dernier élément puis de supprimer
le suivant et de mettre suivant à NULL. Il faut que la liste ne soit pas vide et traiter le cas ou il n'y a
qu'un seul élément dans la liste, le premier
*(*P.suivant).suivant = NULL
Tête
10 20 70
NULL
P
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément en fin de la liste
La suppression à la fin suppose de se positionner sur l'avant dernier élément puis de supprimer
le suivant et de mettre suivant à NULL. Il faut que la liste ne soit pas vide et traiter le cas ou il n'y a
qu'un seul élément dans la liste, le premier
Libérer(*P.suivant)
Tête
10 20 70
NULL
P
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément en fin de la liste
La suppression à la fin suppose de se positionner sur l'avant dernier élément puis de supprimer
le suivant et de mettre suivant à NULL. Il faut que la liste ne soit pas vide et traiter le cas ou il n'y a
qu'un seul élément dans la liste, le premier
Libérer(*P.suivant)
*P.suivant ⃪NULL
Tête
10 20
NULL
P
SUPPRESSION UN ÉLÉMENT
CORRESPONDANT À UN CRITÈRE
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément correspondant à un critère
L'objectif cette fois est de supprimer un élément quelconque de la liste en fonction d'un critère
donné.
Le critère ici est que le champ val de l'élément soit égal à une valeur donnée.
La recherche s'arrête si un élément répond au critère et nous supprimons uniquement le
premier élément trouvé s'il y en a un.
Comme pour les suppressions précédentes la liste ne doit pas être vide.
Il faut prendre en compte le cas où l'élément à supprimer est le premier de la liste.
Pour tous les autre éléments il faut disposer de l'élément qui précédé celui à supprimer afin de
pouvoir reconstruire la chaine.
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément correspondant à un critère
1er Cas : si la valeur à supprimer est celle du premier élément
Tête
10 20 70
Val = 10
NULL
Precedent
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément correspondant à un critère
1er Cas : si la valeur à supprimer est celle du premier élément
Tête
10 20 70
Val = 10
NULL
aSupprimer
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément correspondant à un critère
1er Cas : si la valeur à supprimer est celle du premier élément
Tête
20 70
Val = 10
NULL
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément correspondant à un critère
2ème Cas : chercher la première occurrence à supprimer
aSupprimer
Tête
10 20 70
Val = 20
NULL
Precedent
I. LISTES CHAÎNÉES SIMPLES
Suppression d'un élément correspondant à un critère
2ème Cas : chercher la première occurrence à supprimer
aSupprimer
Tête
10 20 70
Val = 20
NULL
Precedent
Suppression d'un élément correspondant à un critère
Algorithme de la procédure Supprimer_occ1
Procédure Supprimer_Occ1(var Tete_Liste : PNoeud; val : entier)
Var
courant, precedent : PNoeud
Début
Si (estVide(Tete_Liste) Alors
Ecrire("Liste vide !!!!")
Sinon Si(*Tete_Liste.donnee = val) Alors
Supprimer_début(Tete_Liste)
Sinon
courant ⃪ Tete_Liste
TantQue(courant≠NULL && *courant.donnee ≠ val)faire
precedent ⃪ courant
courant ⃪ *courant.suivant
finTantQue
Si courant.donnee = val Alors
*precedent.suivant ⃪ *courant.suivant
Libérer(courant)
finSi
finSi
Fin
LES LISTES DOUBLEMENT CHAÎNÉES
NULL NULL
II. LISTES DOUBLEMENT CHAÎNÉES
Définition
Une liste doublement chaînée ou bidirectionnelle est telle que chaque élément de la
liste contient un champ qui pointe sur l'élément précédent et un champ qui pointe
sur l'élément suivant.
De ce fait, la liste peut être parcourue dans les deux sens.
Chaque nœud de la liste est constitué de trois parties :
un champ qui contient L'adresse un champ qui contient L'adresse
de l'élément précédent(Pointeur) de l'élément suivant(Pointeur)
un champ de données
DÉCLARATION
II. LISTES DOUBLEMENT CHAÎNÉES
Déclaration En algorithme
TYPE
Nom_noeud= Enregistrement
donnee : Type_donnee
suivant : Pointeur sur Nom_noeud
precedent : Pointeur sur Nom_noeud
FinNom_noeud
Nom_Liste = Pointeur sur Nom_noeud
NB.
Une liste doublement chaînée peut être représentée par un enregistrement composé de champs :
o Un pointeur sur le premier élément (Tete)
ListeRepere= Enregistrement
o Un pointeur sur le dernier élément (Queue) Tete : Pointeur sur Nom_noeud
Queue : Pointeur sur Nom_noeud
FinListeRepere
II. LISTES DOUBLEMENT CHAÎNÉES
Déclaration En C
//Définition de la structure Nom_Noeud
typedef struct nom_Noeud
{
type_donnee data;
struct nom_noeud* next;
struct nom_noeud* previous;
} Nom_Noeud;
//Définition de la liste chaînée
typedef Nom_Noeud * Nom_Liste;
NB.
Pour faciliter la manipulation de la liste, on définit le nouveau type Nom_Liste comme étant un
pointeur sur un Nom_Noeud.
II. LISTES DOUBLEMENT CHAÎNÉES
Déclaration d'une structure repère (contient l'adresse du premier et dernier élément)
Pour avoir le contrôle de la liste il est préférable de sauvegarder l'adresse du premier et du
dernier élément.
typedef struct listeRepere
{
struct nom_noeud* tete;
struct nom_noeud* queue;
} Nom_ListeDC;
Créer une Liste chaînée simple(LDC) vide.
Tester si une LCS est vide
Ajouter un élément à une LDC(au début, à la fin
et avant ou après un élément donné)
Supprimer un élément d'une LDC OPERATIONS SUR LES
Chercher un élément dans une LDC LISTES DOUBLEMENT
Trier les éléments d'une LDC(croissant et
décroissant)
CHAÎNÉES
Fusionner deux LDC,
Etc..
II. LISTES DOUBLEMENT CHAÎNÉES
Soit les déclarations suivantes :
Déclaration En algorithme Déclaration En C
TYPE //Définition de la structure Nom_Noeud
typedef struct noeud
Noeud = Enregistrement {
donnee : entier int donnee;
suivant : Pointeur sur Noeud struct noeud* suivant;
struct noeud* precedent;
precedent : Pointeur sur Noeud
}Noeud;
FinNoeud // Définition de la structure repère
ListeDC= Enregistrement typedef struct listeRepere
Tete : Pointeur sur Nom_noeud {
struct noeud* tete;
Queue : Pointeur sur Nom_noeud struct noeud* queue;
FinListeDC }ListeDC;
//Définition de la liste chaînée
PNoeud = Pointeur sur Nœud typedef Noeud* PNoeud;
PListeDC = Pointeur sur ListeDC typedef ListeDC* PListeDC;
CRÉATION D'UNE LISTE DOUBLEMENT CHAÎNÉE
VIDE (INITIALISATION DE LA LISTE)
TESTER SI UNE LISTE DOUBLEMENT CHAÎNÉE
EST VIDE
II. LISTES DOUBLEMENT CHAÎNÉES
Création d'une liste chaînée simple vide (initialisation de la liste)
Algorithme de la procédure Creer_Liste
Procédure Créer_Liste(var LDC : PListeDC)
Début
LDC->Tete ⃪ NULL
LDC->Queue ⃪ NULL
Fin
Implémentation de la procédure Creer_Liste en C
void initialisation(PListeDC LDC)
{
int main()
LDC->tete = NULL;
{
LDC->queue =NULL;
PListeDC LDC = (PListeDC)malloc(sizeof(ListeDC));
}
initialisation(LDC);
}
II. LISTES DOUBLEMENT CHAÎNÉES
Tester si une liste doublement chaînée est vide
Algorithme de la fonction estVide
Fonction estVide(LDC : PListeDC):booléen
Début
Retourner LDC->Tete=NULL
Fin
Implémentation de la procédure Creer_Liste en C
int estVide(PListeDC LDC)
{
return LDC->Tete==NULL;
}
AJOUTER UN ÉLÉMENT (NOEUD)
AU DÉBUT(TÊTE) D'UNE LISTE
DOUBLEMENT CHAÎNÉE
II. LISTES DOUBLEMENT CHAÎNÉES
Ajouter un élément(nœud) au début d'une liste(en tête)
1er cas : La liste est vide
Tete Queue
NULL
Tete Queue Tete Queue
1 1 1
NULL NULL NULL NULL NULL
II. LISTES DOUBLEMENT CHAÎNÉES
Ajouter un élément(nœud) au début d'une liste(en tête)
2ème cas : La liste n'est pas vide
Tete Queue
1 2
NULL NULL
Tete Queue
0 1 2
NULL NULL
NULL
II. LISTES DOUBLEMENT CHAÎNÉES
Ajouter un élément(nœud) au début d'une liste(en tête)
2ème cas : La liste n'est pas vide
Tete Queue
1 2
NULL NULL
Tete Queue
0 1 2
NULL NULL
II. LISTES DOUBLEMENT CHAÎNÉES
Ajouter un élément(nœud) au début d'une liste(en tête)
2ème cas : La liste n'est pas vide
Tete Queue
1 2
NULL NULL
Tete Queue
0 1 2
NULL NULL
II. LISTES DOUBLEMENT CHAÎNÉES
Ajouter un élément(nœud) au début d'une liste(en tête)
Procédure Ajout_Tete (var LDC : PListeDC; val : Entier)
Var
nouveau : PNoeud
Début
nouveau ⃪ allouer (taille (Noeud))
*nouveau.donnee ⃪ val
*nouveau.precedent ⃪ NULL
*nouveau.suivant ⃪ TeteListe
Si (LDC->Tete ≠ NULL) alors
LDC->Tete.precedent ⃪ nouveau
FinSi
LDC->Tete ⃪ nouveau
Si (LDC->Queue = NULL) alors
LDC->Queue ⃪ nouveau
FinSi
Fin
II. LISTES DOUBLEMENT CHAÎNÉES
Ajouter un élément(nœud) au début d'une liste(en tête) En C
void InsererEnTete(PListeDC LDC, int NvDonnee)
{
PNoeud nouveau = (PNoeud)malloc(sizeof(Noeud));
if(!nouveau) { puts("Mémoire insuffisainte !"); exit(EXIT_FAILURE); }
nouveau->donnee = NvDonnee; //ou bien (*nouveau).donnee = NvDonnee
nouveau->precedent = NULL;
if(estVide(LDC))
{
nouveau->suivant = NULL;
LDC->queue = nouveau;
}
else
{
nouveau->suivant = LDC->tete;
LDC->tete->precedent = nouveau;
}
LDC->tete = nouveau;
}