Académique Documents
Professionnel Documents
Culture Documents
Université de Nantes
Département Informatique
2023/2024
Guillaume Cantin
guillaume.cantin@univ-nantes.fr
Retour sur les tableaux
Avantages et inconvénients des tableaux
I Avantages :
accès rapide par indice ;
stockage de plusieurs valeurs de façon consécutive (efficace).
I Inconvénients :
la mémoire est bloquée même pour une occupation partielle ;
la suppression d’un élément implique le décalage des éléments
suivants ;
l’insertion force le décalage des éléments suivants ;
le changement de taille nécessite de recopier tous les éléments.
1 / 57
1. Listes chaı̂nées
Listes chaı̂nées : définition
I Un nœud contient :
le champ de données (type primitif ou enregistrement),
le lien vers le nœud suivant.
2 / 57
Image intuitive
3 / 57
Image intuitive
Type t_noeud = e n r e g i s t r e m e n t
t_data data
pointeur vers t_noeud suivant
fin e n r e g i s t r e m e n t
1
Usage abusif du latin data (données), pluriel de datum (donnée). 5 / 57
Tête et queue d’une liste chaı̂née
6 / 57
2. Insertion dans une liste chaı̂née
Insertion en tête
7 / 57
Insertion en tête
7 / 57
Insertion en tête
7 / 57
Algorithme d’insertion en tête
8 / 57
Algorithme d’insertion en tête
// Fonction d ’insertion en t ê te
f o n c t i o n insereTeteFonc ( pointeur vers t_noeud ancienN ,
t_data nouvelleD ) : pointeur vers t_noeud
v ariable : pointeur vers t_noeud nouveauN ;
début
nouveauN ← allocation ( t_noeud ) // allocation dynamique
m é moire ( nouveauN ). data ← nouvelleD
m é moire ( nouveauN ). suivant ← ancienN
r e t o u r n e r nouveauN
fin
}
// Structure t_noeud
struct t_noeud {
t_data data ;
t_noeud * suivant ;
};
// Fonction d ’ insertion en t ê te
t_noeud * insereTeteFonc ( t_noeud * teteListe , t_data nouvelleD ){
t_noeud * nouveauN ;
nouveauN = new t_noeud ;
nouveauN - > data = nouvelleD ;
nouveauN - > suivant = ancienN ;
return nouveauN ;
}
11 / 57
Inconvénient des insertions en tête successives
12 / 57
Inconvénient des insertions en tête successives
12 / 57
Inconvénient des insertions en tête successives
A A
12 / 57
Inconvénient des insertions en tête successives
A A A
12 / 57
Inconvénient des insertions en tête successives
A A A A
12 / 57
Inconvénient des insertions en tête successives
A A A A A
12 / 57
Inconvénient des insertions en tête successives
A A A A A A
12 / 57
Inconvénient des insertions en tête successives
A A A A A A
12 / 57
Insertion en queue
13 / 57
Insertion en queue
14 / 57
Algorithme d’insertion en queue
La boucle de type tant que peut être traduite en C++ des deux
façons suivantes :
// solution 1
p = pTete
while (p - > suivant != nullptr ){
p = p - > suivant ;
}
// solution 2
for ( p = pTete ; p - > suivant != nullptr ; p =p - > suivant ){
// Rien de sp é cial , on se d é cale
}
16 / 57
Construction d’une liste chaı̂née par insertions en queue suc-
cessives
17 / 57
Effet des insertions en queue successives
18 / 57
Effet des insertions en queue successives
18 / 57
Effet des insertions en queue successives
A A
18 / 57
Effet des insertions en queue successives
A A A
18 / 57
Effet des insertions en queue successives
A A A A
18 / 57
Effet des insertions en queue successives
A A A A A
18 / 57
Effet des insertions en queue successives
A A A A A A
18 / 57
Effet des insertions en queue successives
A A A A A A
18 / 57
Insertion dans l’ordre
I S’il existe une relation d’ordre sur les données, on peut effectuer
une insertion qui maintient la liste ordonnée.
I Cela nécessite de se déplacer le long de la liste avec deux pointeurs
temporaires p et q, pour trouver la bonne position où insérer le
nouveau nœud.
Une fois cette position trouvée :
on alloue un nouveau nœud,
on réalise les chaı̂nages nécessaires.
I Si la liste est vide, ou si la liste ne contient qu’un nœud, le traite-
ment peut être différent.
On peut alors construire une liste de données ordonnées.
19 / 57
Schéma de l’insertion dans l’ordre
20 / 57
Schéma de l’insertion dans l’ordre
384
p q
20 / 57
Schéma de l’insertion dans l’ordre
384
p q
384
p q
20 / 57
Schéma de l’insertion dans l’ordre
384
p q
384
p q
384
p q
20 / 57
3. Parcours, chaı̂nage, fusion
Parcours
21 / 57
Recherche dans une liste
23 / 57
Chaı̂nage de deux listes
23 / 57
Chaı̂nage de deux listes
p L2
23 / 57
Chaı̂nage de deux listes
p L2
Pour préserver L1, on peut créer une nouvelle liste L3 qui reçoit
les éléments de L1 puis ceux de L2 (voir TD C, exercice 2).
24 / 57
Chaı̂nage de deux listes
Pour préserver L1, on peut créer une nouvelle liste L3 qui reçoit
les éléments de L1 puis ceux de L2 (voir TD C, exercice 2).
24 / 57
Fusion de deux listes ordonnées
25 / 57
Fusion de deux listes ordonnées
25 / 57
Fusion de deux listes ordonnées
25 / 57
Fusion de deux listes ordonnées
26 / 57
Suppression de la tête
27 / 57
Suppression de la tête
27 / 57
Suppression de la tête
27 / 57
Suppression de la tête
27 / 57
Suppression de la tête
27 / 57
Suppression de la tête
28 / 57
Suppression totale de la liste
29 / 57
Exemple d’exécution
algorithme principal
variable :
pointeur vers t_noeud L
t_data nain
début
1 nain ← ( " Bombur " , 1 . 10 )
2 L ← NULL
3 insereTeteProc (L , nain )
4 é crire ( m é moire ( L ). data ). nom
5 é crire L , m é moire ( L ). suivant
6 sup pr ess io nTo ta le ( L )
fin
30 / 57
algorithme principal
variable :
pointeur vers t_noeud L
t_data nain
début
1 nain ← ( " Bombur " , 1 . 10 )
2 L ← NULL
3 insereTeteProc (L , nain )
4 é crire ( m é moire ( L ). data ). nom
5 é crire L , m é moire ( L ). suivant
6 sup pr ess io nTo ta le ( L )
fin
@1 @34 @73
Ligne L nain Remarques, affichages
début ? ? Allocations de L et nain
1 ? (”Bombur”, 1.10)
2 NULL (”Bombur”, 1.10)
3 @73 (”Bombur”, 1.10) ((”Bombur”, 1.10), NULL) Appel → allocation dynamique d’un t noeud.
4 @73 (”Bombur”, 1.10) ((”Bombur”, 1.10), NULL) Affiche : Bombur
5 @73 (”Bombur”, 1.10) ((”Bombur”, 1.10), NULL) Affiche : @73, NULL
6 NULL (”Bombur”, 1.10) Appel → désallocation dynamique du t noeud.
fin Désallocations de L et nain
31 / 57
Simulation de l’exécution
@1 @34 @73
1 ? (”Bombur”, 1.10)
3 @73 (”Bombur”, 1.10) ((”Bombur”, 1.10), NULL) Appel → allocation dynamique d’un t noeud.
32 / 57
Suppression de la queue
33 / 57
Suppression de la queue
34 / 57
Suppression de la queue
35 / 57
Suppression de la queue
p q
35 / 57
Suppression de la queue
p q
35 / 57
Suppression de la queue
p q
35 / 57
Suppression de la queue
p q
p q
35 / 57
Suppression de la queue
p q
p q
p q
35 / 57
Remarques
Type ListeTeteQueue = e n r e g i s t r e m e n t
pointeur vers t_noeud tete
pointeur vers t_noeud queue
fin e n r e g i s t r e m e n t
37 / 57
Exemple en C++ : des listes de caractères
struct t_car {
char carac ;
t_car * suivant ; // Ex é cution
}; Entrez un mot :
using mot = t_car *; infor
void insertionQueue ( mot & m , char c );
void saisie ( mot & m ); Entrez un mot :
mot concat ( mot m1 , mot m2 ); matique
void afficher ( mot m );
void afficher_complet ( mot m ); [0 x55d3b37e5850 ] i
void efface ( mot & m ); [0 x55d3b37e5870 ] n
[0 x55d3b37e5890 ] f
int main (){ [0 x55d3b37e58b0 ] o
mot m1 , m2 , m3 ; [0 x55d3b37e58d0 ] r
saisie ( m1 ); [0 x55d3b37e58f0 ] m
saisie ( m2 ); [0 x55d3b37e5910 ] a
m3 = concat ( m1 , m2 ); [0 x55d3b37e5930 ] t
afficher_c omplet ( m3 ); [0 x55d3b37e5950 ] i
efface ( m1 ); [0 x55d3b37e5970 ] q
efface ( m2 ); [0 x55d3b37e5990 ] u
efface ( m3 ); [0 x55d3b37e59b0 ] e
return 0;
}
38 / 57
Opérations d’insertion et de saisie
40 / 57
Affichage, libération
42 / 57
5. Autres types de listes chaı̂nées
Listes doublement chaı̂nées
Type t_noeud = e n r e g i s t r e m e n t
t_data data
pointeur vers t_noeud suivant
pointeur vers t_noeud precedent
fin e n r e g i s t r e m e n t
43 / 57
Algorithme d’insertion en tête dans une liste doublement
chaı̂née
un pointeur nul !
I On peut aussi rechercher des cycles dans une liste censée être non
circulaire (voir TD C, exercice 5).
45 / 57
6. Application des listes chaı̂nées
Piles et files
I Les listes chaı̂nées sont très utiles pour implémenter des structures
telles que les piles et les files.
Une pile est une structure qui répond au principe dernier arrivé,
premier sorti (en anglais LIFO pour last in, first out).
Une file est une structure qui répond au principe premier arrivé,
premier sorti (en anglais FIFO pour first in, first out).
...
tête de la file
46 / 57
Piles et files
...
tête de la file
I Sur ce schéma :
on entre dans la pile et on sort de la pile par le sommet,
on entre dans la file par la queue, on en sort par la tête.
I Ces structures seront étudiées en ASD1 puis en ASD2.
I On peut tout à fait implémenter les piles et les files en utilisant
des tableaux. 47 / 57
Exemple d’application : les polynômes
P 1 3x −4x2
type t_monome = e n r e g i s t r e m e n t
coeff : R é el
puiss : Entier
suivant : Pointeur vers t_monome
fin e n r e g i s t r e m e n t
type t_polynome = Pointeur vers t_monome
48 / 57
Opérations sur les polynômes
49 / 57
Somme de deux polynômes
50 / 57
Somme de deux polynômes
51 / 57
7. Récursivité
Récursivité
int F a c t o r i e l l e R e c u r s i v e ( int n ){
if ( n <= 1)
return 1;
else
return n * F a c t o r i e l l e R e c u r s i v e (n -1); // appel r é cursif
}
int F a c t o r i e l l e R e c u r s i v e ( int n ){
if ( n <= 1){
return 1;
} else {
cout << " Appel de F a c t o r e l l e R e c u r s i v e ( " << n -1 << " ) " << endl ;
return n * F a c t o r i e l l e R e c u r s i v e (n -1); // appel r é cursif
}
}
// Ex é cution
guigui :∼/ home / ALGO$ ./ factorielle . out
Appel de F a c t o r i e l l e R e c u r s i v e (4)
Appel de F a c t o r i e l l e R e c u r s i v e (3)
Appel de F a c t o r i e l l e R e c u r s i v e (2)
Appel de F a c t o r i e l l e R e c u r s i v e (1)
120
53 / 57
Application aux listes chaı̂nées
I Les nœuds d’une liste chaı̂née ont une structure qui se prête na-
turellement à la programmation récursive.
I Exemple : algorithme récursif d’affichage.
54 / 57
Algorithme récursif d’affichage d’une liste chaı̂née en C++
55 / 57
Récursivité et listes chaı̂nées
56 / 57
Conclusion
Conclusion
57 / 57
Conclusion
57 / 57
Conclusion
57 / 57
Conclusion
57 / 57
Conclusion
57 / 57
Conclusion
57 / 57
Conclusion