1. Chapitre 14
Listes chaˆn´ es
ı e
14.1 La notion de liste
Une liste est une structure de donn´ es qui permet de stocker une s´ quence d’objets d’un mˆ me
e e e
type. En cela, les listes ressemblent aux tableaux. La s´ quence d’entiers 3, 7, 2, 4 peut etre repr´ sent´ e
e ˆ e e
a la fois sous forme de tableau ou de liste. La notation [3, 7, 2, 4] repr´ sentera la liste qui contient
` e
cette s´ quence.
e
Il y a cependant des diff´ rences fondamentales entre listes et tableaux :
e
– Dans un tableau on a acc` s imm´ diat a n’importe quel el´ ment par son indice (acc` s dit al´ atoire),
e e ` ´e e e
tandis que dans une liste chaˆn´ e on a acc` s aux el´ ments un apr` s l’autre, a partir du premier
ı e e ´e e `
el´ ment (acc` s dit s´ quentiel).
´e e e
– Un tableau a une taille fixe, tandis qu’une liste peut augmenter en taille ind´ finiment (on peut
e
toujours rajouter un el´ ment a une liste).
´e `
D´ finition (r´ cursive) :
e e
En consid´ rant que la liste la plus simple est la liste vide (not´ e [ ]), qui ne contient aucun el´ ment,
e e ´e
on peut donner une d´ finition r´ cursive aux listes chaˆn´ es d’´ l´ ments de type T :
e e ı e ee
– la liste vide [ ] est une liste ;
– si e est un el´ ment de type T et l est une liste d’´ l´ ments de type T, alors le couple (e, l) est
´e ee
aussi une liste, qui a comme premier el´ ment e et dont le reste des el´ ments (` partir du second)
´e ´e a
forment la liste l.
Cette d´ finition est r´ cursive, car une liste est d´ finie en fonction d’une autre liste. Une telle
e e e
d´ finition r´ cursive est correcte, car une liste est d´ finie en fonction d’une liste plus courte, qui contient
e e e
un el´ ment de moins. Cette d´ finition permet de construire n’importe quelle liste en partant de la liste
´e e
vide.
Conclusion : la liste chaˆn´ e est une structure de donn´ es r´ cursive.
ı e e e
La validit´ de cette d´ finition r´ cursive peut etre discut´ e d’un point de vue diff´ rent. Elle peut
e e e ˆ e e
etre exprim´ e sous la forme suivante : quelque soit la liste l consid´ r´ e,
ˆ e ee
– soit l est la liste vide [ ],
– soit l peut etre d´ compos´ e en un premier el´ ment e et un reste r de la liste, l=(e, r).
ˆ e e ´e
Cette d´ finition donne une d´ composition r´ cursive des listes. La condition g´ n´ rale d’arrˆ t de
e e e e e e
r´ cursivit´ est pour la liste vide. Cette d´ composition est valide, car la liste est r´ duite a chaque pas
e e e e `
a une liste plus courte d’une unit´ . Cela garantit que la d´ composition m` ne toujours a une liste de
` e e e `
longueur 0, la liste vide (condition d’arrˆ t).
e
1
2. 2 ˆ ´
CHAPITRE 14. LISTES CHAINEES
14.2 Repr´ sentation des listes chaˆn´ es en Java
e ı e
Il y a plusieurs facons de repr´ senter les listes chaˆn´ es en Java. L’id´ e de base est d’utiliser un
¸ e ı e e
enchaˆnement de cellules :
ı
– chaque cellule contient un el´ ment de la liste ;
´e
– chaque cellule contient une r´ f´ rence vers la cellule suivante, sauf la derni` re cellule de la liste
ee e
(qui contient une r´ f´ rence nulle) ;
ee
– la liste donne acc` s a la premi` re cellule, le reste de la liste est accessible en passant de cellule
e ` e
en cellule, suivant leur enchaˆnement.
ı
La figure 14.1 illustre cette repr´ sentation pour la liste exemple ci-dessus [3, 7, 2, 4].
e
liste
3 7 2 4
F IG . 14.1 – Repr´ sentation par enchaˆnement de cellules de la liste [3, 7, 2, 4]
e ı
En Java, les r´ f´ rences ne sont pas d´ finies explicitement, mais implicitement a travers les objets :
ee e `
un objet est repr´ sent´ par une r´ f´ rence vers la zone de m´ moire qui contient ses variables d’instance.
e e ee e
Comme une liste est d´ finie par une r´ f´ rence vers une cellule (la premi` re de la liste), la m´ thode
e ee e e
la plus simple est de repr´ senter une liste par sa premi` re cellule. La classe suivante d´ finit une liste
e e e
d’entiers.
Listing 14.1 – (lien vers le code brut)
1 class Liste {
2 int element ;
3 Liste suivant ;
4
5 L i s t e ( i nt premier , L i s t e r e s t e ){
6 element = premier ;
7 suivant = reste ;
8 }
9 }
Le constructeur de la classe Liste cr´ e une liste comme une premi` re cellule qui contient le
e e
premier el´ ment de la liste et une r´ f´ rence vers le reste de la liste.
´e ee
Remarque : Cette solution a l’inconv´ nient de ne repr´ senter que des listes avec au moins une cel-
e e
lule. La liste vide, qui selon la d´ finition est egalement une liste, ne peut pas etre un objet de
e ´ ˆ
la classe Liste. Il est n´ anmoins possible de repr´ senter la liste vide par une r´ f´ rence nulle.
e e ee
Cette repr´ sentation imparfaite des listes a l’avantage de la simplicit´ et nous l’utiliserons dans
e e
le reste de ce cours.
14.3 Op´ rations sur les listes chaˆn´ es
e ı e
Nous etudierons les op´ rations les plus importantes sur les listes chaˆn´ es, qui seront repr´ sent´ es
´ e ı e e e
comme des m´ thodes de la classe Liste.
e
Remarque : Puisque la classe Liste ne peut pas repr´ senter la liste vide, des op´ rations de base
e e
comme le test de liste vide ou l’action de vider une liste ne peuvent pas etre des m´ thodes de la
ˆ e
3. ´ ˆ ´
14.3. OPERATIONS SUR LES LISTES CHAINEES 3
classe Liste. Ces op´ rations doivent etre effectu´ es a l’ext´ rieur de la classe Liste, par le
e ˆ e ` e
programme qui utilise les listes.
Conform´ ment a leur d´ finition, les listes sont des structures r´ cursives. Par cons´ quent, les
e ` e e e
op´ rations sur les listes s’expriment naturellement par des algorithmes r´ cursifs. En mˆ me temps,
e e e
les listes sont des structures lin´ aires, parfaitement adapt´ es a un parcours it´ ratif. Nous donnerons
e e ` e
aussi la variante it´ rative des op´ rations sur listes, a titre comparatif.
e e `
La repr´ sentation de la classe Liste ci-dessous montre sous forme de m´ thodes les op´ rations
e e e
sur listes que nous discuterons.
Listing 14.2 – (lien vers le code brut)
1 class Liste {
2 int element ;
3 Liste suivant ;
4
5 public L i s t e ( i nt premier , L i s t e r e s t e ){
6 element = premier ;
7 suivant = reste ;
8 }
9
10 public int premier ( ) { . . . }
11 public Liste reste ( ) { . . . }
12 public v o i d m o d i f i e P r e m i e r ( i n t elem ) { . . . }
13 public void m o d i f i e R e s t e ( L i s t e r e s t e ) { . . . }
14 public int longueur ( ) { . . . }
15 public b o o l e a n c o n t i e n t ( i n t elem ) { . . . }
16 public L i s t e i n s e r t i o n D e b u t ( i n t elem ) { . . . }
17 public void c o n c a t e n a t i o n ( L i s t e l i s t e ) { . . . }
18 public L i s t e s u p p r e s s i o n P r e m i e r ( i n t elem ) { . . . }
19 }
14.3.1 Op´ rations sans parcours de liste
e
Pour ces op´ rations il n’y a pas de variantes it´ ratives et r´ cursives, l’action est r´ alis´ e directe-
e e e e e
ment sur la tˆ te de la liste.
e
´e
Obtenir le premier el´ ment et le reste de la liste
Ces op´ rations sont r´ alis´ es par les m´ thodes premier (qui retourne le premier el´ ment de la
e e e e ´e
liste), respectivement reste (qui retourne le reste de la liste).
En fait, ces m´ thodes ne sont pas n´ cessaires, au sens strict du terme, puisque dans la classe
e e
Liste on a acc` s direct aux variables d’instance element et suivant.
e
Nous verrons plus tard que l’acc` s direct aux variables d’instance est d´ conseill´ dans la program-
e e e
mation orient´ e-objet. A la place, on pr´ ferre “cacher” les variables d’instance et donner acc` s a leur
e e e `
valeurs a travers des m´ thodes. Ceci fera l’objet d’un prochain cours.
` e
Aussi, ces m´ thodes correspondent aux el´ ments de la d´ composition r´ cursive d’une liste et sont
e ´e e e
bien adapt´ es a l’´ criture d’algorithmes r´ cursifs sur les listes.
e ` e e
Listing 14.3 – (lien vers le code brut)
1 public int premier (){
4. 4 ˆ ´
CHAPITRE 14. LISTES CHAINEES
2 return element ;
3 }
4
5 public Liste r e s t e (){
6 return s u i v a n t ;
7 }
Remarque : Il ne faut pas oublier que premier et reste sont des m´ thodes de la classe Liste,
e
donc une instruction comme return element signifie return this.element. Une
liste est repr´ sent´ e par sa premi` re cellule, donc return this.element retourne l’´ l´ ment
e e e ee
de cette premi` re cellule.
e
´e
Modifier le premier el´ ment et le reste de la liste
Ces op´ rations sont r´ alis´ es par les m´ thodes modifiePremier (qui modifie le premier el´ ment
e e e e ´e
de la liste), respectivement modifieReste (qui modifie le reste de la liste).
Ces m´ thodes permettent donc de modifier les composants element et suivant de la premi` re
e e
cellule de la liste. Elles sont compl´ mentaires aux m´ thodes premier et reste, qui permettent de
e e
consulter ces mˆ mes composants.
e
Leur pr´ sence dans la classe Liste correspond au mˆ me principe que celui evoqu´ pour premier
e e ´ e
et reste : remplacer l’acc` s direct aux variables d’instance par des appels de m´ thodes.
e e
Listing 14.4 – (lien vers le code brut)
1 p u b l i c v o i d m o d i f i e P r e m i e r ( i n t elem ) {
2 e l e m e n t = elem ;
3 }
4
5 public void m o d i f i e R e s t e ( L i s t e r e s t e ){
6 suivant = reste ;
7 }
e ´e
Ins´ rer un el´ ment en tˆ te de liste
e
L’insertion en tˆ te de liste est r´ alis´ e par la m´ thode insertionDebut. C’est une op´ ration
e e e e e
simple, car elle n´ cessite juste un acc` s a la tˆ te de la liste initiale. On cr´ e une nouvelle cellule, a
e e ` e e `
laquelle on enchaˆne l’ancienne liste.
ı
La m´ thode insertionDebut retourne une nouvelle liste, car la liste initiale est modifi´ e par
e e
l’insertion (la premi` re cellule de la nouvelle liste est diff´ rente).
e e
Listing 14.5 – (lien vers le code brut)
1 p u b l i c L i s t e i n s e r t i o n D e b u t ( i n t elem ) {
2 r e t u r n new L i s t e ( elem , t h i s ) ;
3 }
14.3.2 Op´ rations avec parcours de liste - variante it´ rative
e e
Ces op´ rations n´ cessitent un parcours complet ou partiel de la liste. Dans la variante it´ rative,
e e e
le parcours est r´ alis´ a l’aide d’une r´ f´ rence qui part de la premi` re cellule de la liste et suit l’en-
e e` ee e
chaˆnement des cellules.
ı
5. ´ ˆ ´
14.3. OPERATIONS SUR LES LISTES CHAINEES 5
La figure 14.2 illustre le principe du parcours it´ ratif d’une liste a l’aide d’une r´ f´ rence ref.
e ` ee
ref ........ ref
liste
e1 ... ei ... en
F IG . 14.2 – Parcours it´ ratif d’une liste a l’aide d’une r´ f´ rence
e ` ee
Calculer la longueur d’une liste
Cette op´ ration, r´ alis´ e par la m´ thode longueur, n´ cessite un parcours complet de la liste
e e e e e
pour compter le nombre de cellules trouv´ es.
e
Listing 14.6 – (lien vers le code brut)
1 public int longueur (){
2 i n t compteur = 0 ;
3 Liste ref=this ;
4 while ( r e f != n u l l ){
5 c o m p t e u r ++;
6 ref=ref . reste (); / / ou r e f = r e f . s u i v a n t
7 }
8 return compteur ;
9 }
Remarque : La r´ f´ rence ref est positionn´ e au d´ but sur la premi` re cellule de la liste et avance
ee e e e
jusqu’` ce qu’elle devient nulle a la fin de la liste. Chaque fois qu’elle pointe vers une nouvelle
a `
cellule, le compteur est incr´ ment´ . Remarquez que l’avancement dans la liste se fait en utili-
e e
sant la m´ thode reste de la cellule courante, ou sinon l’acc` s direct a la variable d’instance
e e `
suivant.
´e `
V´ rifier l’appartenance d’un el´ ment a une liste
e
Cette op´ ration, r´ alis´ e par la m´ thode contient, n´ cessite un parcours partiel de la liste pour
e e e e e
chercher l’´ l´ ment en question. Si l’´ l´ ment est retrouv´ , le parcours s’arrˆ te a ce moment-l` , sinon il
ee ee e e ` a
continue jusqu’` la fin de la liste.
a
Listing 14.7 – (lien vers le code brut)
1 p u b l i c b o o l e a n c o n t i e n t ( i n t elem ) {
2 Liste ref=this ;
3 while ( r e f != n u l l ){
4 i f ( r e f . p r e m i e r ( ) == elem ) / / ou r e f . e l e m e n t==e l e m
5 return true ; / / l ’ element a ete retrouve
6 else ref=ref . reste (); / / ou r e f = r e f . s u i v a n t
7 }
8 return f a l s e ; / / l ’ element n ’ a pas e t e r e t r o u v e
9 }
6. 6 ˆ ´
CHAPITRE 14. LISTES CHAINEES
Remarque : L’arrˆ t du parcours en cas de succ` s se fait en retournant directement true pendant
e e
l’ex´ cution de la boucle, ce qui termine a la fois la boucle et la fonction. Remarquez que le test
e `
de l’´ l´ ment courant point´ par la r´ f´ rence utilise la m´ thode premier de la cellule courante,
ee e ee e
ou sinon l’acc` s direct a la variable d’instance element.
e `
Concat´ nation de deux listes
e
Cette op´ ration, r´ alis´ e par la m´ thode concatenation, rajoute a la fin de la liste courante
e e e e `
toutes les cellules de la liste pass´ e en param` tre. Elle n´ cessite un parcours complet de la liste cou-
e e e
rante, afin de trouver sa derni` re cellule.
e
La liste obtenue par concat´ nation a toujours la mˆ me premi` re cellule que la liste initiale. On
e e e
peut dire donc que la liste initiale a et´ modifi´ e, en lui rajoutant par concat´ nation une autre liste.
´e e e
Listing 14.8 – (lien vers le code brut)
1 public void c o n c a t e n a t i o n ( L i s t e l i s t e ){
2 Liste ref=this ;
3 while ( r e f . r e s t e ( ) != n u l l ){ / / ou r e f . s u i v a n t != n u l l
4 ref=ref . reste (); / / ou r e f = r e f . s u i v a n t
5 }
6 / / re f pointe maintenant sur la d e r n i e r e c e l l u l e de l a l i s t e
7 ref . modifieReste ( l i s t e ) ; / / ou r e f . s u i v a n t= l i s t e
8 }
Remarque : La condition de la boucle while change ici, car on veut s’arrˆ ter sur la derni` re cellule et
e e
non pas la d´ passer comme dans les m´ thodes pr´ c´ dentes. Remarquez que l’enchaˆnement des
e e e e ı
deux listes se fait en modifiant la variable d’instance suivant de la derni` re cellule a l’aide
e `
de la m´ thode modifieReste, ou sinon par modification directe de celle-ci.
e
´e
Suppression de la premi` re occurrence d’un el´ ment
e
Cette op´ ration, r´ alis´ e par la m´ thode suppressionPremier, elimine de la liste la premi` re
e e e e ´ e
apparition de l’´ l´ ment donn´ en param` tre (s’il existe). La m´ thode retourne une liste, car la liste
ee e e e
obtenue par suppression peut avoir une autre premi` re cellule que la liste initiale. Ceci arrive quand la
e
cellule elimin´ e est exactement la premi` re de la liste.
´ e e
La suppression d’une cellule de la liste se fait de la mani` re suivante (voir la figure 14.3) :
e
– si la cellule est la premi` re de la liste, la nouvelle liste sera celle qui commence avec la seconde
e
cellule.
– sinon la cellule a un pr´ d´ cesseur ; pour eliminer la cellule il faut la “court-circuiter”, en mo-
e e ´
difiant la variable suivant du pr´ d´ cesseur pour qu’elle pointe vers la mˆ me chose que la
e e e
variable suivant de la cellule.
pred ref pred ref
liste
liste
e e2 ... e1 ... ei e ...
nouvelle liste
F IG . 14.3 – Suppression d’une cellule de la liste
7. ´ ˆ ´
14.3. OPERATIONS SUR LES LISTES CHAINEES 7
Le parcours de la liste a la recherche de l’´ l´ ment donn´ a une particularit´ : si la r´ f´ rence
` ee e e ee
s’arrˆ te sur la cellule qui contient l’´ l´ ment, la suppression n’est plus possible, car on n’a plus acc` s
e ee e
au pr´ d´ cesseur (dans les listes chaˆn´ es on ne peut plus revenir en arri` re).
e e ı e e
La m´ thode utilis´ e est alors de parcourir la liste avec deux r´ f´ rences :
e e ee
– une (ref) qui cherche la cellule a eliminer ;
`´
– une autre (pred) qui se trouve toujours sur le pr´ d´ cesseur de ref.
e e
Listing 14.9 – (lien vers le code brut)
1 p u b l i c L i s t e s u p p r e s s i o n P r e m i e r ( i n t elem ) {
2 Liste ref=this ; / / r e f e r e n c e qui cherche elem
3 L i s t e pred= null ; / / predecesseur , i n i t i a l i s e a nu l l
4 w h i l e ( r e f ! = n u l l && r e f . p r e m i e r ( ) ! = elem ) { / / r e c h e r c h e elem
5 pred = r e f ; / / avance pred
6 ref = ref . reste (); / / avance r e f
7 }
8 i f ( r e f != n u l l ){ / / elem t r o u v e dans l a c e l l u l e r e f
9 i f ( p r e d == n u l l ) / / p r e m i e r e c e l l u l e de l a l i s t e
10 return r e f . r e s t e ( ) ; / / r e t o u r n e l e r e s t e de l a l i s t e
11 else { / / m i l i e u de l a l i s t e
12 p r e d . m o d i f i e R e s t e ( r e f . r e s t e ( ) ) ; / / m o d i f i e l e s u i v a n t du p r e d e c e s s e u r
13 return t h i s ; / / p r e m i e r e c e l l u l e non m o d i f i e e
14 }
15 }
16 e l s e return t h i s ; / / e l e m e n t non t r o u v e
17 }
14.3.3 Op´ rations avec parcours de liste - variante r´ cursive
e e
Ces op´ rations sont bas´ es sur une d´ composition r´ cursive de la liste en un premier el´ ment et
e e e e ´e
le reste de la liste (voir la figure 14.4). Le cas le plus simple (condition d’arrˆ t) est la liste avec une
e
seule cellule.
premier reste
liste
e ...
F IG . 14.4 – D´ composition r´ cursive d’une liste
e e
Calcul r´ cursif de la longueur d’une liste
e
La formule r´ cursive est :
e
liste.longueur() = 1 si reste==null
1 + reste.longueur() si reste!=null
La fonction r´ cursive longueur s’´ crit alors tr` s facilement, comme suit :
e e e
Listing 14.10 – (lien vers le code brut)
1 public int longueur (){
8. 8 ˆ ´
CHAPITRE 14. LISTES CHAINEES
2 Liste resteListe = reste () ; / / ou r e s t e L i s t e = s u i v a n t ;
3 i f ( r e s t e L i s t e == n u l l ) / / condition d ’ arret
4 return 1;
5 e l s e return 1 + r e s t e L i s t e . longueur ( ) ;
6 }
e e `
V´ rification r´ cursive de l’appartenance a une liste
La formule r´ cursive est :
e
liste.contient(e) = true si premier==e
false si premier!=e et reste==null
reste.contient(e) si premier!=e et reste!=null
Remarquez que dans ce cas il y a deux conditions d’arrˆ t : quand on trouve l’´ l´ ment recherch´ ou
e ee e
quand la liste n’a plus de suite (reste est vide). La fonction r´ cursive contient s’´ crit alors comme
e e
suit :
Listing 14.11 – (lien vers le code brut)
1 p u b l i c b o o l e a n c o n t i e n t ( i n t elem ) {
2 i f ( elem == p r e m i e r ( ) ) r e t u r n t r u e ; / / ou e l e m==e l e m e n t
3 Liste resteListe = reste () ; / / ou r e s t e L i s t e = s u i v a n t ;
4 i f ( r e s t e L i s t e == n u l l ) / / condition d ’ arret
5 return f a l s e ;
6 e l s e r e t u r n r e s t e L i s t e . c o n t i e n t ( elem ) ;
7 }
Concat´ nation r´ cursive de deux listes
e e
L’action r´ cursive est :
e
liste.concatenation(l): reste=l si reste==null
reste.concatenation(l) si reste!=null
Si la liste a une seule cellule (pas de cellule suivante, reste est vide), alors il faut modifier la
r´ f´ rence vers la cellule suivante pour enchaˆner la liste param` tre. Sinon, il suffit de concat´ ner le
ee ı e e
reste avec la liste param` tre.
e
Listing 14.12 – (lien vers le code brut)
1 public void c o n c a t e n a t i o n ( L i s t e l i s t e ){
2 Liste resteListe = reste () ; / / ou r e s t e L i s t e = s u i v a n t ;
3 i f ( r e s t e L i s t e == n u l l ) / / condition d ’ arret
4 modifieReste ( l i s t e ) ; / / ou s u i v a n t= l i s t e
5 else resteListe . concatenation ( l i s t e );
6 }
9. ´ ˆ ´
14.3. OPERATIONS SUR LES LISTES CHAINEES 9
e e ´e
Suppression r´ cursive de la premi` re occurrence d’un el´ ment
La formule r´ cursive est :
e
liste.suppressionPremier(e) =
reste si premier==e
Liste(premier, null) si premier!=e et reste==null
Liste(premier, reste.suppressionPremier(e)) si premier!=e et
reste != null
Si le premier el´ ment de la liste est celui recherch´ , le r´ sultat sera le reste de la liste. Sinon, il
´e e e
faut supprimer r´ cursivement l’´ l´ ment recherch´ du reste. Mais le r´ sultat de cette suppression est
e ee e e
une liste qui provient de reste, donc elle n’a plus le premier el´ ment de la liste initiale. Il faut donc le
´e
rajouter en tˆ te de liste.
e
Listing 14.13 – (lien vers le code brut)
1 p u b l i c L i s t e s u p p r e s s i o n P r e m i e r ( i n t elem ) {
2 Liste resteListe = reste () ; / / ou r e s t e L i s t e = s u i v a n t ;
3 i f ( elem == p r e m i e r ( ) ) / / ou e l e m==e l e m e n t
4 return r e s t e L i s t e ;
5 e l s e i f ( r e s t e L i s t e == n u l l ) r e t u r n new L i s t e ( p r e m i e r ( ) , n u l l ) ;
6 e l s e r e t u r n new L i s t e ( p r e m i e r ( ) , r e s t e L i s t e . s u p p r e s s i o n P r e m i e r ( elem ) ) ;
7 }
Remarque : L’inconv´ nient de cette m´ thode est qu’on cr´ e des copies de toutes les cellules qui ne
e e e
contiennent pas l’´ l´ ment recherch´ . Pour eviter cela, la d´ finition doit m´ langer calcul et effets
ee e ´ e e
de bord, comme suit :
liste.suppressionPremier(e) =
reste si premier==e
liste si premier!=e et reste==null
liste apr`s l’action reste=reste.suppressionPremier(e)
e
si premier!=e et reste!=null
Listing 14.14 – (lien vers le code brut)
1 p u b l i c L i s t e s u p p r e s s i o n P r e m i e r ( i n t elem ) {
2 Liste resteListe = reste () ; / / ou r e s t e L i s t e = s u i v a n t ;
3 i f ( elem == p r e m i e r ( ) ) / / ou e l e m==e l e m e n t
4 return r e s t e L i s t e ;
5 e l s e i f ( r e s t e L i s t e == n u l l ) r e t u r n t h i s ;
6 else {
7 m o d i f i e R e s t e ( r e s t e L i s t e . s u p p r e s s i o n P r e m i e r ( elem ) ) ;
8 return t h i s ;
9 }
10 }
10. 10 ˆ ´
CHAPITRE 14. LISTES CHAINEES
14.4 Listes tri´ es
e
Nous nous int´ ressons maintenant aux listes chaˆn´ es dans lesquelles les el´ ments respectent un
e ı e ´e
ordre croissant. Dans ce cas, les m´ thodes de recherche, d’insertion et de suppression sont diff´ rentes.
e e
L’ordre des el´ ments permet d’arrˆ ter plus tˆ t la recherche d’un el´ ment qui n’existe pas dans la liste.
´e e o ´e
Aussi, l’insertion ne se fait plus en d´ but de liste, mais a la place qui pr´ serve l’ordre des el´ ments.
e ` e ´e
Nous utiliserons une classe ListeTriee qui est tr` s similaire a la classe Liste, mais dans la-
e `
quelle on s’int´ resse uniquement aux m´ thodes de recherche (contientTriee), d’insertion (insertionTriee)
e e
et de suppression (suppressionTriee). Les autres m´ thodes sont identiques a celles de la classe
e `
Liste.
Listing 14.15 – (lien vers le code brut)
1 class ListeTriee {
2 int element ;
3 ListeTriee suivant ;
4
5 public L i s t e T r i e e ( i nt premier , L i s t e T r i e e r e s t e ){
6 element = premier ;
7 suivant = reste ;
8 }
9
10 public int premier ( ) { . . . }
11 public ListeTriee reste ( ) { . . . }
12 public v o i d m o d i f i e P r e m i e r ( i n t elem ) { . . . }
13 public void m o d i f i e R e s t e ( L i s t e T r i e e r e s t e ) { . . . }
14
15 p u b l i c b o o l e a n c o n t i e n t T r i e e ( i n t elem ) { . . . }
16 p u b l i c L i s t e T r i e e i n s e r t i o n T r i e e ( i n t elem ) { . . . }
17 p u b l i c L i s t e T r i e e s u p p r e s s i o n T r i e e ( i n t elem ) { . . . }
18 }
14.4.1 Recherche dans une liste tri´ e
e
La diff´ rence avec la m´ thode contient de Liste est que dans le parcours de la liste on peut
e e
s’arrˆ ter d` s que la cellule courante contient un el´ ment plus grand que celui recherch´ . Comme tous
e e ´e e
les el´ ments suivants vont en ordre croissant, ils seront egalement plus grands que l’´ l´ ment recherch´ .
´e ´ ee e
Variante iterative :
Listing 14.16 – (lien vers le code brut)
1 p u b l i c b o o l e a n c o n t i e n t T r i e e ( i n t elem ) {
2 ListeTriee ref=this ;
3 w h i l e ( r e f ! = n u l l && r e f . p r e m i e r ( ) <= elem ) {
4 i f ( r e f . p r e m i e r ( ) == elem )
5 return true ;
6 else ref=ref . reste ();
7 }
8 return f a l s e ;
9 }
11. ´
14.4. LISTES TRIEES 11
Variante r´ cursive :
e
Listing 14.17 – (lien vers le code brut)
1 p u b l i c b o o l e a n c o n t i e n t T r i e e ( i n t elem ) {
2 i f ( elem == p r e m i e r ( ) ) r e t u r n t r u e ;
3 i f ( elem < p r e m i e r ( ) ) r e t u r n f a l s e ;
4 ListeTriee resteListe = reste () ;
5 i f ( r e s t e L i s t e == n u l l )
6 return f a l s e ;
7 e l s e r e t u r n r e s t e L i s t e . c o n t i e n t T r i e e ( elem ) ;
8 }
14.4.2 Insertion dans une liste tri´ e
e
L’insertion d’un el´ ment doit se faire a la bonne place dans la liste. La bonne place est juste avant
´e `
la premi` re cellule qui contient un el´ ment plus grand que celui a ins´ rer.
e ´e ` e
Variante iterative :
La figure 14.5 montre les deux cas d’insertion :
– en d´ but de liste.
e
Elle est similaire alors a l’op´ ration insertionDebut de la classe Liste
` e
– en milieu de liste.
La recheche de la position d’insertion se fait alors avec une m´ thode similaire a celle uti-
e `
lis´ e pour la m´ thode suppressionPremier de la classe Liste, avec deux r´ f´ rences.
e e ee
Le pr´ d´ cesseur doit etre modifi´ pour pointer vers la nouvelle cellule, tandis que celle-ci doit
e e ˆ e
pointer vers la cellule courante (ref).
pred ref pred ref
liste
liste
nouvelle liste e1 ... e1 ... ep er ...
e
e
F IG . 14.5 – Insertion dans une liste tri´ e
e
Dans la figure 14.5, a droite, la r´ f´ rence ref peut ne pas pointer vers une cellule. Ceci arrive quand
` ee
l’´ l´ ment a ins´ rer est plus grand que tous les el´ ments de la liste. Dans ce cas, l’insertion se fait a
ee ` e ´e `
la fin de la liste, donc au moment de l’arrˆ t de la recherche, ref est nulle et pred est sur la derni` re
e e
cellule de la liste. Ce cas est identique a celui pr´ sent´ dans la figure 14.5, a la variable suivant de
` e e `
la nouvelle cellule on donne tout simplement la valeur de ref.
Listing 14.18 – (lien vers le code brut)
1 p u b l i c L i s t e T r i e e i n s e r t i o n T r i e e ( i n t elem ) {
2 ListeTriee ref=this ; / / r e f e r e n c e qui cherche elem
3 L i s t e T r i e e pred= null ; / / predecesseur , i n i t i a l i s e a nu l l
4 w h i l e ( r e f ! = n u l l && r e f . p r e m i e r ( ) < elem ) { / / recherche position
5 pred = r e f ; / / avance pred
6 ref = ref . reste (); / / avance r e f
12. 12 ˆ ´
CHAPITRE 14. LISTES CHAINEES
7 }
8 i f ( p r e d == n u l l ) / / i n s e r t i o n au d e b u t
9 r e t u r n new L i s t e T r i e e ( elem , t h i s ) ;
10 else { / / i n s e r t i o n au m i l i e u de l a l i s t e
11 L i s t e T r i e e n o u v eau = new L i s t e T r i e e ( elem , r e f ) ;
12 p r e d . m o d i f i e R e s t e ( n o u v eau ) ; / / m o d i f i e l e s u i v a n t du p r e d e c e s s e u r
13 return t h i s ; / / p r e m i e r e c e l l u l e non m o d i f i e e
14 }
15 }
Variante r´ cursive :
e
Nous utilisons le mˆ me sch´ ma de d´ composition r´ cursive de la liste, en un premier el´ ment
e e e e ´e
(premier) et un reste de la liste (reste). L’insertion r´ cursive suit le sch´ ma suivant :
e e
liste.insertionTriee(e) =
ListeTriee(e, liste) si e<=premier
liste apr`s reste=ListeTriee(e, null)
e si e>premier et reste==null
liste apr`s reste=reste.insertionTriee(e) si e>premier et reste!=null
e
Si l’´ l´ ment a ins´ rer est plus petit ou egal a premier, l’insertion se fera en tˆ te de liste. Sinon,
ee ` e ´ ` e
l’insertion se fera r´ cursivement dans le reste. Si reste est vide, alors reste sera remplac´ par la nouvelle
e e
cellule a ins´ rer. Si reste n’est pas vide, l’insertion se fait r´ cursivement dans reste et le r´ sultat
` e e e
remplace l’ancien reste.
Listing 14.19 – (lien vers le code brut)
1 p u b l i c L i s t e T r i e e i n s e r t i o n T r i e e ( i n t elem ) {
2 i f ( elem <= p r e m i e r ( ) )
3 r e t u r n new L i s t e T r i e e ( elem , t h i s ) ;
4 else {
5 ListeTriee resteListe = reste ();
6 i f ( r e s t e L i s t e == n u l l )
7 m o d i f i e R e s t e ( new L i s t e T r i e e ( elem , n u l l ) ) ;
8 else
9 m o d i f i e R e s t e ( r e s t e L i s t e . i n s e r t i o n T r i e e ( elem ) ) ;
10 return t h i s ;
11 }
12 }
14.4.3 Suppression dans une liste tri´ e
e
La suppression de la premi` re occurrence d’un el´ ment dans une liste tri´ e est assez similaire
e ´e e
a la suppression dans une liste non tri´ e. La seule chose qui change est la recherche de la cellule a
` e `
supprimer, qui b´ n´ ficie du tri des valeurs. Aussi, si plusieurs occurrences de l’´ l´ ment existent, elles
e e ee
sont forc´ ment l’une a la suite de l’autre a cause du tri. Il serait donc plus simple d’´ liminer toutes les
e ` ` e
occurrences de l’´ l´ ment que dans le cas des listes non tri´ es. Nous nous limiterons cependant ici a la
ee e `
suppression de la premi` re occurrence seulement.
e
Variante iterative :
13. 14.5. UN EXEMPLE DE PROGRAMME QUI UTILISE LES LISTES 13
Par rapport a la m´ thode suppressionPremier de la classe Liste, ici le parcours de la
` e
liste a la recherche de l’´ l´ ment ne se fait que tant que ref pointe une valeur plus petite que celui-ci.
` ee
Une fois le parcours arrˆ t´ , la seule diff´ rence est qu’il faut v´ rifier que ref pointe vraiment la valeur
ee e e
recherch´ e.
e
Listing 14.20 – (lien vers le code brut)
1 p u b l i c L i s t e s u p p r e s s i o n T r i e e ( i n t elem ) {
2 Liste ref=this ; / / r e f e r e n c e qui cherche elem
3 L i s t e pred= null ; / / predecesseur , i n i t i a l i s e a nu l l
4 w h i l e ( r e f ! = n u l l && r e f . p r e m i e r ( ) < elem ) { / / r e c h e r c h e elem
5 pred = r e f ; / / avance pred
6 ref = ref . reste (); / / avance r e f
7 }
8 i f ( r e f ! = n u l l && r e f . p r e m i e r ( ) == elem ) { / / e l e m t r o u v e d a n s l a c e l l u l e r e f
9 i f ( p r e d == n u l l ) / / p r e m i e r e c e l l u l e de l a l i s t e
10 return r e f . r e s t e ( ) ; / / r e t o u r n e l e r e s t e de l a l i s t e
11 else { / / m i l i e u de l a l i s t e
12 p r e d . m o d i f i e R e s t e ( r e f . r e s t e ( ) ) ; / / m o d i f i e l e s u i v a n t du p r e d e c e s s e u r
13 return t h i s ; / / p r e m i e r e c e l l u l e non m o d i f i e e
14 }
15 }
16 e l s e return t h i s ; / / e l e m e n t non t r o u v e
17 }
Variante r´ cursive :
e
Par rapport a la variante r´ cursive de la m´ thode suppressionPremier de la classe Liste,
` e e
une nouvelle condition d’arrˆ t est rajout´ e :
e e
quand l’´ l´ ment a eliminer est plus petit que premier, il n’existe sˆ rement pas dans la liste et celle-ci
ee `´ u
est retourn´ e non modifi´ e.
e e
Listing 14.21 – (lien vers le code brut)
1 p u b l i c L i s t e s u p p r e s s i o n T r i e e ( i n t elem ) {
2 Liste resteListe = reste () ;
3 i f ( elem == p r e m i e r ( ) )
4 return r e s t e L i s t e ;
5 e l s e i f ( elem < p r e m i e r ( ) ) r e t u r n t h i s ; / / nouvelle condition d ’ arret
6 e l s e i f ( r e s t e L i s t e == n u l l ) r e t u r n t h i s ;
7 else {
8 m o d i f i e R e s t e ( r e s t e L i s t e . s u p p r e s s i o n T r i e e ( elem ) ) ;
9 return t h i s ;
10 }
11 }
14.5 Un exemple de programme qui utilise les listes
Consid´ rons un exemple simple de programme qui manipule des listes chaˆn´ es en utilisant la
e ı e
classe Liste.
14. 14 ˆ ´
CHAPITRE 14. LISTES CHAINEES
Le programme lit une suite de nombres entiers termin´ e par la valeur 0 et construit une liste avec
e
ces entiers (sauf le 0 final). La liste doit garder les el´ ments dans l’ordre dans lequel ils sont introduits.
´e
Egalement, une valeur ne doit etre stock´ e qu’une seule fois dans la liste.
ˆ e
Le programme lit ensuite une autre suite de valeurs, egalement termin´ e par un 0, avec lesquelles
´ e
il construit une autre liste, sans se soucier de l’ordre des el´ ments. Les el´ ments de cette seconde liste
´e ´e
devront etre elimin´ s de la liste initiale.
ˆ ´ e
A la fin, le programme affiche ce qui reste de la premi` re liste.
e
Remarque : Pour garder les el´ ments dans l’ordre d’introduction, l’insertion d’un nouvel el´ ment
´e ´e
doit se faire en fin de liste. La m´ thode insertionDebut ne convient donc pas. La solution
e
est d’utiliser la m´ thode concatenation.
e
Remarque : Pour qu’un el´ ment soit stock´ une seule fois dans la liste, il faut d’abord v´ rifier s’il
´e e e
n’y est pas d´ j` , a l’aide de la m´ thode contient.
ea ` e
Voici le programme qui r´ alise ces actions :
e
Listing 14.22 – (lien vers le code brut)
1 public cl as s ExempleListes{
2 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
3 / / 1. Creation premiere l i s t e
4 T e r m i n a l . e c r i r e S t r i n g l n ( ” E n t r e z l e s v a l e u r s t e r m i n e e s p a r un 0 : ” ) ;
5 Liste l i s t e = null ; / / l i s t e a construire
6 do {
7 i nt val = Terminal . l i r e I n t ( ) ;
8 i f ( v a l ==0) break ;
9 i f ( l i s t e == n u l l )
10 l i s t e = new L i s t e ( v a l , n u l l ) ;
11 else i f (! l i s t e . contient ( val ))
12 l i s t e . c o n c a t e n a t i o n ( new L i s t e ( v a l , n u l l ) ) ;
13 } while ( true ) ;
14
15 / / 2. Creation seconde l i s t e
16 T e r m i n a l . e c r i r e S t r i n g l n ( ” V a l e u r s a e l i m i n e r ( t e r m i n e e s p a r un 0 ) : ” ) ;
17 Liste l i s t e 2 = null ;
18 do {
19 i nt val = Terminal . l i r e I n t ( ) ;
20 i f ( v a l ==0) break ;
21 i f ( l i s t e 2 == n u l l )
22 l i s t e 2 = new L i s t e ( v a l , n u l l ) ;
23 else l i s t e 2 = l i s t e 2 . insertionDebut ( val ) ;
24 } while ( true ) ;
25
26 / / 3 . E l i m i n a t i o n de l a p r e m i e r e l i s t e
27 f o r ( L i s t e r e f = l i s t e 2 ; r e f != n u l l ; r e f = r e f . r e s t e ( ) ) {
28 i f ( l i s t e == n u l l ) break ; / / plus rien a eliminer
29 l i s t e = l i s t e . suppressionPremier ( r ef . premier ( ) ) ;
30 }
31
32 / / 4. Affichage l i s t e restante
33 Terminal . e c r i r e S t r i n g l n ( ” Valeurs r e s t a n t e s : ” ) ;
34 f o r ( L i s t e r e f = l i s t e ; r e f != n u l l ; r e f = r e f . r e s t e ( ) )
35 Terminal . e c r i r e S t r i n g ( ” ” + r e f . premier ( ) ) ;
15. 14.5. UN EXEMPLE DE PROGRAMME QUI UTILISE LES LISTES 15
36 Terminal . sautDeLigne ( ) ;
37 }
38 }