26/04/2010
1
Ch. PAUL Algorithmique - Listes chaînées récursives 1
RECURSIVITELISTES CHAINEES
Insertion à la bonne place,Affichage pré et post ordre,
Désallocation de la liste,Suppression dans une liste.
2
Listes chaînées récursivesdéfinition
Une liste est une entité définie récursivement par : Un élément de tête, Un reste (encore une liste comptant un élément de moins).
La liste vide représente l'élément de base (en C le NULL).
Toutes les méthodes récursives appliquées aux listes partent de ce postulat.
A noter que le langage LISP de traitement des listes intègre de facto ce paradigme.
Ch. PAUL Algorithmique - Listes chaînées récursives
26/04/2010
2
3
Données manipulées Représentation en C
typedef struct maillon
{
char info[NMAX] ;
struct maillon* suiv;
} MAIL ;
Nota : dans ce qui suit le champ info est une chaîne de caractères.
Ch. PAUL Algorithmique - Listes chaînées récursives
Lis te
in fo
su ivsu iv
info info
N U LL
4
Création d'un maillon
MAIL* CreerMaillon(void)
{
MAIL* N=(MAIL *)malloc(sizeof(MAIL));
if (N == NULL)
{ printf("\nErreur allocation memoire");
return NULL;
}
printf("\nDonner un mot : ");
scanf("%s", N->info);
N->suiv = NULL;
return N;
} /* fin CreerMaillon */
Attention : la création du maillon doit se faire en dehors de l'insertion récursive.
Ch. PAUL Algorithmique - Listes chaînées récursives
26/04/2010
3
Insertion à la bonne place méthode récursive
5Ch. PAUL Algorithmique - Listes chaînées récursives
Représentation récursive des listes : liste vide ouliste constituée d'une tête et d'un reste.
insertion élémentaire :(1) insertion dans une liste vide.
insertion dans une liste constituée d'une tête etd'un reste, deux cas:(2)L'élément est plus petit que l'élément de tête (3)L'élément est plus grand que l'élément de tête
Insertion à la bonne place liste vide, liste quelconque
6Ch. PAUL Algorithmique - Listes chaînées récursives
liste vide : revient à retourner la liste constituée du nouvelélément.
liste quelconque :soit l'élément est plus petit que l'élément de têteet on pratique un ajout en tête de la liste,soit l'élément est plus grand que l'élément de têteet on relance récursivement l'insertion sur le restede la liste.
26/04/2010
4
Insertion à la bonne place liste vide, liste quelconque
7Ch. PAUL Algorithmique - Listes chaînées récursives
NULL Liste XX
Liste XX
XX
??
Liste AA XX
Liste ZZXX Reste
Resteinsertion
tête ?? = AA
insertion
récursive reste
?? = ZZ
8
Insertion à la bonne place
MAIL* insBP(MAIL *T, MAIL *N)
{
if (T == NULL) return N;
Ch. PAUL Algorithmique - Listes chaînées récursives
(1) insertion liste vide
26/04/2010
5
9
Insertion à la bonne place
MAIL* insBP(MAIL *T, MAIL *N)
{
if (T == NULL) return N;
if (strcmp(N->info,T->info)<0)
{ N->suiv = T;
return N;
}
Ch. PAUL Algorithmique - Listes chaînées récursives
(2) insertion en tête
10
Insertion à la bonne place
MAIL* insBP(MAIL *T, MAIL *N)
{
if (T == NULL) return N;
if (strcmp(N->info,T->info)<0)
{ N->suiv = T;
return N;
}
else
{ T->suiv= insBP(T->suiv,N);
return T;
}
} /* fin insBP */
Remarque : plus besoin d'un pointeur précédentCh. PAUL Algorithmique - Listes chaînées récursives
(3) insertion reste
26/04/2010
6
Insertion à la bonne place Attention
11Ch. PAUL Algorithmique - Listes chaînées récursives
L'insertion dans le reste de la liste impose dereconstituer le chaînage de la liste à chaque appelrécursif (l'insertion en tête dans le reste a pumodifier la valeur de la liste). D'où l'instruction :
T->suiv= insBP(T->suiv,N)
Dans tous les cas, la valeur de la liste (pointeur sur latête) est renvoyée à la fonction appelante.
return T
Traitements pré ordre
12Ch. PAUL Algorithmique - Listes chaînées récursives
Les pré-traitements (ou traitements en pré-ordre)s'exécutent avant l'appel récursif sur le reste de laliste.
Il en résulte que la tête de la liste est traitée avant lereste de la liste.
L'affichage en pré-ordre conserve donc l'ordre de laliste.
26/04/2010
7
13
Parcours en pré-ordre
void ParcoursPre(MAIL *T)
{
if (T != NULL)
{
printf("\n%s", T->info);
ParcoursPre(T->suiv);
}
} /* fin ParcoursPre */
Ch. PAUL Algorithmique - Listes chaînées récursives
tête de la liste traitée avant le reste de la liste
14
Parcours en pré-ordre
void ParcoursPre(MAIL *T)
{
if (T != NULL)
{
printf("\n%s", T->info);
ParcoursPre(T->suiv);
}
} /* fin ParcoursPre */
Parcours en pré-ordre le traitement (printf) se fait avant l'appel récursif . L'affichage se fait du début vers la fin.
1 2 3 4 5Ch. PAUL Algorithmique - Listes chaînées récursives
tête de la liste traitée avant le reste de la liste
26/04/2010
8
Traitements post ordre
15Ch. PAUL Algorithmique - Listes chaînées récursives
Les post-traitements (ou traitements en post-ordre)s'exécutent après l'appel récursif sur le reste de laliste. Il en résulte que la tête de la liste est traitéeaprès le reste de la liste.
L'affichage en post-ordre inverse donc l'ordre de laliste.
La désalocation de la liste en post-ordre évited'utiliser une variable supplémentaire.
16
Affichage en post-ordre
void ParcoursPost(MAIL *T)
{
if (T != NULL)
{
ParcoursPost(T->suiv);
printf("\n%s", T->info);
}
} /* fin ParcoursPost */
Ch. PAUL Algorithmique - Listes chaînées récursives
tête de la liste traitée après le reste de la liste
26/04/2010
9
17
Affichage en post-ordre
void ParcoursPost(MAIL *T)
{
if (T != NULL)
{
ParcoursPost(T->suiv);
printf("\n%s", T->info);
}
} /* fin ParcoursPost */
Parcours en post-ordre le traitement (printf) se fait après l'appel récursif. L'affichage se fait de la fin au début dans l'ordre inverse
5 4 3 2 1
Ch. PAUL Algorithmique - Listes chaînées récursives
tête de la liste traitée après le reste de la liste
18
Désalocation de la liste
void DesalouerListe(MAIL *T)
{
if (T != NULL)
{
DesalouerListe(T->suiv);
free(T);
}
} /* fin DesalouerListe */
La désalocation est un traitement de type post-ordre
Attention : mettre la tête de la liste à NULL après la désalocation
Ch. PAUL Algorithmique - Listes chaînées récursives
tête de la liste traitée après le reste de la listepas nécessaire d'utiliser une variable auxiliaire
26/04/2010
10
Suppression d'un maillon principe récursif
19Ch. PAUL Algorithmique - Listes chaînées récursives
(1) Si la liste est vide arrêter.
Sinon, dans une liste constituée d'une tête et d'unreste, vérifier si le maillon à supprimer est la tête dela liste :
(2) Si c'est la tête de la liste, renvoyer auprogramme appelant le reste de la liste et arrêter.(3) Sinon relancer récursivement la suppressionsur le reste de la liste.
Suppression d'un maillonliste avec tête et reste
20Ch. PAUL Algorithmique - Listes chaînées récursives
Liste SS
Liste XX Reste
Reste SS
Liste Reste
SS
Reste SSListe XX
Suppression du maillon de tête
Suppression
dans le reste
26/04/2010
11
21
MAIL* rm(MAIL *T, char nom[])
{ MAIL* R;
if (T == NULL)
{printf("\nLe nom n'est pas dans la liste");
return T;
}
Suppression d'un maillon de la liste
Ch. PAUL Algorithmique - Listes chaînées récursives
(1) liste vide : arrêt
22
MAIL* rm(MAIL *T, char nom[])
{ MAIL* R;
if (T == NULL)
{printf("\nLe nom n'est pas dans la liste");
return T;
}
if (strcmp(nom,T->info)==0)
{ R= T;
T= T->suiv;
free(R);
return T;
}
Ch. PAUL Algorithmique - Listes chaînées récursives
Suppression d'un maillon de la liste
(2) maillon trouvé:
renvoyer le reste de
la liste au
programme appelant
26/04/2010
12
23
MAIL* rm(MAIL *T, char nom[])
{ MAIL* R;
if (T == NULL)
{printf("\nLe nom n'est pas dans la liste");
return T;
}
if (strcmp(nom,T->info)==0)
{ R= T;
T= T->suiv;
free(R);
return T;
}
else
{ T->suiv= rm(T->suiv,nom);
return T;
}
} /* fin rm */Ch. PAUL Algorithmique - Listes chaînées récursives
Suppression d'un maillon de la liste
(3) relancer
récursivement sur le
reste de la liste
Suppression d'un maillon Attention
24Ch. PAUL Algorithmique - Listes chaînées récursives
La suppression dans le reste de la liste impose dereconstituer le chaînage de la liste à chaque appelrécursif (la suppression en tête dans le reste a pumodifier la valeur de la liste). D'où l'instruction :
T->suiv= rm(T->suiv,N)
Dans tous les cas, la valeur de la liste (pointeur sur latête) est renvoyée à la fonction appelante.
return T
26/04/2010
13
Suppression Exemple
25Ch. PAUL Algorithmique - Listes chaînées récursives
L'exemple qui suit correspond à la suppression (en3ème place) d'un maillon.
Il s'agit de supprimer le maillon contenant l'info :"charles" dans la liste :
albertbill
charles
dino
26
>> appel de >> rm(T=1024, nom=“charles”)
T->info=“albert”, T->suiv=2048,
<< retour de << T= ???
info :: albert
suiv :: 2048
info :: bill
suiv :: 4064
info :: charles
suiv :: 6128
info :: dino
suiv :: NULL
1024 2048 4064 6128
Ch. PAUL Algorithmique - Listes chaînées récursives
26/04/2010
14
27
>> appel de >> rm(T=1024, nom=“charles”)
T->info=“albert”, T->suiv=2048,
T->suiv=rm(2048,”charles”)
>> appel de >> rm(T=2048, nom=“charles”)
T->info=“bill”, T->suiv=4064,
T->suiv=rm(4064,”charles”)
<< retour de << T= ???
<< retour de << T = ???
info :: albert
suiv :: 2048
info :: bill
suiv :: 4064
info :: charles
suiv :: 6128
info :: dino
suiv :: NULL
1024 2048 4064 6128
Ch. PAUL Algorithmique - Listes chaînées récursives
28
>> appel de >> rm(T=1024, nom=“charles”)
T->info=“albert”, T->suiv=2048,
T->suiv=rm(2048,”charles”)
>> appel de >> rm(T=2048, nom=“charles”)
T->info=“bill”, T->suiv=4064,
T->suiv=rm(4064,”charles”)
>> appel de >> rm(T=4064, nom=“charles”)
T->info=“charles”, T->suiv=6128,
R=T, T=6128
<< retour de << T=???
<< retour de << T=???
info :: albert
suiv :: 2048
info :: bill
suiv :: 4064
info :: charles
suiv :: 6128
info :: dino
suiv :: NULL
1024 2048 4064 6128
Ch. PAUL Algorithmique - Listes chaînées récursives
26/04/2010
15
29
>> appel de >> rm(T=1024, nom=“charles”)
T->info=“albert”, T->suiv=2048,
T->suiv=rm(2048,”charles”)
>> appel de >> rm(T=2048, nom=“charles”)
T->info=“bill”, T->suiv=4064,
T->suiv=rm(4064,”charles”)
>> appel de >> rm(T=4064, nom=“charles”)
T->info=“charles”, T->suiv=6128,
R=T, T=6128
suppression de R
<< retour de << T=???
<< retour de << T=???
info :: albert
suiv :: 2048
info :: bill
suiv :: 4064
info :: charles
suiv :: 6128
info :: dino
suiv :: NULL
1024 2048 4064 6128
Ch. PAUL Algorithmique - Listes chaînées récursives
30
>> appel de >> rm(T=1024, nom=“charles”)
T->info=“albert”, T->suiv=2048,
T->suiv=rm(2048,”charles”)
>> appel de >> rm(T=2048, nom=“charles”)
T->info=“bill”, T->suiv=4064,
T->suiv=rm(4064,”charles”)
>> appel de >> rm(T=4064, nom=“charles”)
T->info=“charles”, T->suiv=6128,
R=T, T=6128
suppression de R
<< retour de << T= 6128
<< retour de << T = ???
<< retour de << T = ???
info :: albert
suiv :: 2048
info :: bill
suiv :: 6128
info :: dino
suiv :: NULL
1024 2048 6128
Ch. PAUL Algorithmique - Listes chaînées récursives
26/04/2010
16
31
>> appel de >> rm(T=1024, nom=“charles”)
T->info=“albert”, T->suiv=2048,
T->suiv=rm(2048,”charles”)
>> appel de >> rm(T=2048, nom=“charles”)
T->info=“bill”, T->suiv=4064,
T->suiv=rm(4064,”charles”)
>> appel de >> rm(T=4064, nom=“charles”)
T->info=“charles”, T->suiv=6128,
R=T, T=6128
suppression de R
<< retour de << T= 6128
<< retour de << T = 2048
<< retour de << T = ???
info :: albert
suiv :: 2048
info :: bill
suiv :: 6128
info :: dino
suiv :: NULL
1024 2048 6128
Ch. PAUL Algorithmique - Listes chaînées récursives
32
>> appel de >> rm(T=1024, nom=“charles”)
T->info=“albert”, T->suiv=2048,
T->suiv=rm(2048,”charles”)
>> appel de >> rm(T=2048, nom=“charles”)
T->info=“bill”, T->suiv=4064,
T->suiv=rm(4064,”charles”)
>> appel de >> rm(T=4064, nom=“charles”)
T->info=“charles”, T->suiv=6128,
R=T, T=6128
suppression de R
<< retour de << T= 6128
<< retour de << T = 2048
<< retour de << T = 1024
info :: albert
suiv :: 2048
info :: bill
suiv :: 6128
info :: dino
suiv :: NULL
1024 2048 6128
Ch. PAUL Algorithmique - Listes chaînées récursives
26/04/2010
17
33
>> appel de >> rm(T=1024, nom=“charles”)
T->info=“albert”, T->suiv=2048,
T->suiv=rm(2048,”charles”)
>> appel de >> rm(T=2048, nom=“charles”)
T->info=“bill”, T->suiv=4064,
T->suiv=rm(4064,”charles”)
>> appel de >> rm(T=4064, nom=“charles”)
T->info=“charles”, T->suiv=6128,
R=T, T=6128
suppression de R
<< retour de << T= 6128
<< retour de << 2048
<< retour de << 1024
info :: albert
suiv :: 2048
info :: bill
suiv :: 4064
info :: charles
suiv :: 6128
info :: dino
suiv :: NULL
1024 2048 4064 6128
info :: albert
suiv :: 2048
info :: bill
suiv :: 6128
info :: dino
suiv :: NULL
1024 2048 6128
Ch. PAUL Algorithmique - Listes chaînées récursives