Vous êtes sur la page 1sur 16

Chapitre 1

Listes chanes
1.1

La notion de liste

Une liste est une structure de donnes qui permet de stocker une squence dobjets dun mme
type. En cela, les listes ressemblent aux tableaux. La squence dentiers 3, 7, 2, 4 peut tre reprsente
la fois sous forme de tableau ou de liste. La notation [3, 7, 2, 4] reprsentera la liste qui contient
cette squence.
Il y a cependant des diffrences fondamentales entre listes et tableaux :
Dans un tableau on a accs immdiat nimporte quel lment par son indice (accs dit alatoire), tandis que dans une liste chane on a accs aux lments un aprs lautre, partir du
premier lment (accs dit squentiel).
Un tableau a une taille fixe, tandis quune liste peut augmenter en taille indfiniment (on peut
toujours rajouter un lment une liste).
Dfinition (rcursive) :
En considrant que la liste la plus simple est la liste vide (note [ ]), qui ne contient aucun lment,
on peut donner une dfinition rcursive aux listes chanes dlments de type T :
la liste vide [ ] est une liste ;
si e est un lment de type T et l est une liste dlments de type T, alors le couple (e, l) est
aussi une liste, qui a comme premier lment e et dont le reste des lments ( partir du second)
forment la liste l.
Cette dfinition est rcursive, car une liste est dfinie en fonction dune autre liste. Une telle
dfinition rcursive est correcte, car une liste est dfinie en fonction dune liste plus courte, qui contient
un lment de moins. Cette dfinition permet de construire nimporte quelle liste en partant de la liste
vide.
Conclusion : la liste chane est une structure de donnes rcursive.
La validit de cette dfinition rcursive peut tre discute dun point de vue diffrent. Elle peut
tre exprime sous la forme suivante : quelque soit la liste l considre,
soit l est la liste vide [ ],
soit l peut tre dcompose en un premier lment e et un reste r de la liste, l=(e, r).
Cette dfinition donne une dcomposition rcursive des listes. La condition gnrale darrt de
rcursivit est pour la liste vide. Cette dcomposition est valide, car la liste est rduite chaque pas
une liste plus courte dune unit. Cela garantit que la dcomposition mne toujours une liste de
longueur 0, la liste vide (condition darrt).
1

1.2. REPRSENTATION DES LISTES CHANES EN JAVA CHAPITRE 1. LISTES CHANES

1.2

Reprsentation des listes chanes en Java

Il y a plusieurs faons de reprsenter les listes chanes en Java. Lide de base est dutiliser un
enchanement de cellules :
chaque cellule contient un lment de la liste ;
chaque cellule contient une rfrence vers la cellule suivante, sauf la dernire cellule de la liste
(qui contient une rfrence nulle) ;
la liste donne accs la premire cellule, le reste de la liste est accessible en passant de cellule
en cellule, suivant leur enchanement.
La figure 1.1 illustre cette reprsentation pour la liste exemple ci-dessus [3, 7, 2, 4].

liste

F IGURE 1.1 Reprsentation par enchanement de cellules de la liste [3, 7, 2, 4]


En Java, les rfrences ne sont pas dfinies explicitement, mais implicitement travers les objets :
un objet est reprsent par une rfrence vers la zone de mmoire qui contient ses variables dinstance.
Comme une liste est dfinie par une rfrence vers une cellule (la premire de la liste), la solution
la plus simple est de reprsenter une liste par sa premire cellule. La classe suivante dfinit une liste
dentiers.
class ElementListe{
int valeur;
ElementListe suivant;
ElementListe(int valeur, ElementListe suivant){
this.valeur = valeur;
this.suivant = suivant;
}
}

Cependant, cette reprsentation ne fonctionne que pour les listes non vide (un ElementListe
contient forcment au moins une valeur).
On reprsente donc dhabitude les listes par deux classes : une classe pour les lments, et une
classe pour la liste elle-mme, qui contient une rfrence vers son premier lment.
class Liste {
ElementListe premier;
}

Si premier est null, la liste est vide.

1.3

Oprations sur les listes chanes, version itrative

Nous tudierons les oprations les plus importantes sur les listes chanes, qui seront implmentes comme des mthodes de la classe Liste.
Conformment leur dfinition, les listes sont des structures rcursives. Par consquent, les oprations sur les listes sexpriment naturellement par des algorithmes rcursifs. En mme temps, les
2

c
NFA031 CNAM
2012

CHAPITRE 1. LISTES1.3.
CHANES
OPRATIONS SUR LES LISTES CHANES, VERSION ITRATIVE
listes sont des structures linaires, parfaitement adaptes un parcours itratif. Nous allons proposer dabord une version des classes qui implmentera les mthode de manire itrative, et nous en
donnerons ensuite une version rcursive.
La reprsentation de la classe Liste ci-dessous montre sous forme de mthodes les oprations
sur listes que nous discuterons.
public class Liste {
public boolean estVide() {}
public ElementListe getDebut() {}
public void ajouterAuDebut(int v) {}
public int getLongueur() {}
public boolean contient(int v) {}
public void retirerPremiereOccurrence(int v) {}
public void concatener(Liste l) {}
}

1.3.1

La classe ElementListe

Nous avons dcid de placer toute la logique des mthodes dans la classe Liste. Ce nest pas
forcment la seule solution, mais le code obtenu sera plus facile expliquer.
La classe ElementListe est donc rduite sa plus simple expression : un lment de liste a
une valeur, et est suivi dun autre lment de liste (qui peut tre ventuellement null si notre lment
est le dernier).
La classe est dote de plusieurs constructeurs et des accesseurs ncessaires.
public class ElementListe {
private int valeur;
private ElementListe suivant;
public ElementListe(int valeur, ElementListe suivant) {
this.valeur = valeur;
this.suivant = suivant;
}
/**
*Cre un lment de liste sans successeur.
*@param v
*/
public ElementListe(int v) {
this.valeur = v;
this.suivant = null;
}
public int getValeur() {
return valeur;
}
public void setValeur(int valeur) {
this.valeur = valeur;
}

c
NFA031 CNAM
2012

1.3. OPRATIONS SUR LES LISTES CHANES, VERSIONCHAPITRE


ITRATIVE
1. LISTES CHANES

public ElementListe getSuivant() {


return suivant;
}
public void setSuivant(ElementListe suivant) {
this.suivant = suivant;
}
}

Consulter la valeur dun lment et accder llment suivant


Ces oprations sont ralises par les mthodes getValeur (qui retourne la valeur associe un
lment e de la liste), respectivement getSuivant (qui retourne llment qui suit e, ou null si e
est le dernier lment).
En rendant les variables dinstance valeur et suivant private, nous nous sommes interdit dy
accder directement, do lcriture de ces mthodes, appeles accesseurs.
Nous verrons plus tard que laccs direct aux variables dinstance est dconseill dans la programmation oriente-objet. A la place, on prferre cacher les variables dinstance et donner accs leur
valeurs travers des mthodes. Ceci fera lobjet dun prochain cours.
Remarque : Il ne faut pas oublier que getValeur et getSuivant sont des mthodes de la
classe ElementListe, donc une instruction comme return valeur signifie return
this.valeur
.
Modifier la valeur et llment suivant
Ces oprations sont ralises par les mthodes setValeur (qui modifie la valeur dun lment
de la liste), respectivement setSuivant (qui change llment suivant).
Ces mthodes permettent donc de modifier les composants valeur et suivant dune cellule
de la liste. Elles sont complmentaires aux mthodes getValeur() et getSuivant(), qui permettent de consulter ces mmes composants.
Leur prsence dans la classe ElementListe correspond au mme principe que celui voqu
pour getValeur() et getSuivant() : remplacer laccs direct aux variables dinstance par des
appels de mthodes.

1.3.2

Oprations sans parcours de liste

Pour ces oprations il ny a pas de variantes itratives et rcursives, laction est ralise directement sur lobjet Liste.
Obtenir le premier lment de la liste
Cette opration est ralise par la mthode getPremier() qui retourne le premier ElementListe
de la liste.
4

c
NFA031 CNAM
2012

CHAPITRE 1. LISTES1.3.
CHANES
OPRATIONS SUR LES LISTES CHANES, VERSION ITRATIVE

public ElementListe getPremier() {


return premier;
}

Savoir si une liste est vide


Une liste est vide si son premier lment est null. La mthode estVide() de la classe
Liste est donc :
public boolean estVide() {
return premier == null;
}

Insrer un lment en tte de liste


Linsertion en tte de liste est ralise par la mthode ajouterAuDebut. Cest une opration
simple, car elle ncessite juste un accs la tte de la liste initiale. On cre une nouvelle cellule,
laquelle on enchane lancienne liste.
public void ajouterAuDebut(int v) {
ElementListe ancienPremier= premier;
premier= new ElementListe(v,ancienPremier);
}

1.3.3

Oprations avec parcours de liste - variante itrative

Ces oprations ncessitent un parcours complet ou partiel de la liste. Dans la variante itrative, le
parcours est ralis laide dune rfrence qui part de la premire cellule de la liste et suit lenchanement des cellules.
La figure 1.2 illustre le principe du parcours itratif dune liste laide dune rfrence ref.

........

ref

ref

liste

e1

...

ei

...

en

F IGURE 1.2 Parcours itratif dune liste laide dune rfrence

Calculer la longueur dune liste


Cette opration, ralise par la mthode getLongueur, ncessite un parcours complet de la liste
pour compter le nombre de cellules trouves.
public int getLongueur() {
int longueur= 0;
ElementListe ref= getPremier();
while (ref != null) {
longueur++;

c
NFA031 CNAM
2012

1.3. OPRATIONS SUR LES LISTES CHANES, VERSIONCHAPITRE


ITRATIVE
1. LISTES CHANES
ref= ref.getSuivant();
}
return longueur;
}

Remarque : La rfrence ref est positionne au dbut sur la premire cellule de la liste et avance
jusqu ce quelle devient nulle la fin de la liste. Chaque fois quelle pointe vers une nouvelle
cellule, le compteur est incrment. Remarquez que lavancement dans la liste se fait en utilisant
la mthode getSuivant de la cellule courante.
Vrifier lappartenance dun lment une liste
Cette opration, ralise par la mthode contient, ncessite un parcours partiel de la liste pour
chercher llment en question. Si llment est retrouv, le parcours sarrte ce moment-l, sinon il
continue jusqu la fin de la liste.
public boolean contient(int v) {
boolean trouve= false;
ElementListe ref= getPremier();
while (! trouve && ref != null) {
if (ref.getValeur() ==v ) {
trouve= true;
} else {
ref= ref.getSuivant();
}
}
// trouve est vrai implique donc ref.getValeur() ==v
// autre test possible pour la boucle
// while (ref != null && ref.getValeur() != v)
// expliquer lordre des test dans ce cas.
return trouve;
}

Concatnation de deux listes


Cette opration, ralise par la mthode concatener, rajoute la fin de la liste courante toutes
les cellules de la liste passe en paramtre. Elle ncessite un parcours complet de la liste courante,
afin de trouver sa dernire cellule.
La liste obtenue par concatnation a toujours la mme premire cellule que la liste initiale. On
peut dire donc que la liste initiale a t modifie, en lui rajoutant par concatnation une autre liste.
Tel que le code est crit, les lments de la liste l sont partags entre l et la liste l0 laquelle on
la concatne. Une modification ultrieure de l peut avoir des consquences inattendues sur l0. Une
variante plus sre, mais plus coteuse en temps et en espace mmoire serait de dupliquer le contenu
de l.
public void concatener(Liste l) {
if (this.estVide()) {
this.premier= l.getPremier();
} else {
// On parcourt la liste jusqu tre sur

c
NFA031 CNAM
2012

CHAPITRE 1. LISTES1.3.
CHANES
OPRATIONS SUR LES LISTES CHANES, VERSION ITRATIVE
// le dernier lment, celui dont le suivant est null.
ElementListe dernier= this.getPremier();
while (dernier.getSuivant() != null) {
dernier= dernier.getSuivant();
}
// Nous y sommes. dernier correspond au dernier lment
// de la liste, qui existe car celle-ci nest pas vide.
// On fixe donc le suivant de dernier au premier
// lment de la liste l.
dernier.setSuivant(l.getPremier());
}
}

Remarque : La condition de la boucle while change ici, car on veut sarrter sur la dernire cellule et
non pas la dpasser comme dans les mthodes prcdentes. Remarquez que lenchanement des
deux listes se fait en modifiant la variable dinstance suivant de la dernire cellule laide
de la mthode setSuivant.
Dans le mme esprit que lalgorithme de concatnation, on peut crire lajout dun lment en
dernire position dune liste :
public void ajouterALaFin(int v) {
if (estVide()) {
premier= new ElementListe(v);
} else {
// Il y a un dernier lment.
// On le cherche et on ajoute aprs lui.
ElementListe dernier = getDernierElement();
// nous savons que
// dernier.getSuivant() == null => dernier est bien le dernier lment.
dernier.setSuivant(new ElementListe(v));
}
}
/**
*Trouve le dernier lment dune liste non vide.
*Lance une {@link NullPointerException} pour une liste vide.
*@return le dernier lment dune liste
*@throws une NullPointerException si la liste est vide
*/
private ElementListe getDernierElement() {
ElementListe dernier= premier;
while (dernier.getSuivant() != null) {
dernier= dernier.getSuivant();
}
return dernier;
}

(la mthode getDernierElement pourra tre rutilise avec profit dans concatener pour simplifier son criture).
c
NFA031 CNAM
2012

1.3. OPRATIONS SUR LES LISTES CHANES, VERSIONCHAPITRE


ITRATIVE
1. LISTES CHANES
Suppression de la premire occurrence dun lment
Cette opration, ralise par la mthode retirerPremiereOccurrence, limine de la liste
la premire apparition de llment donn en paramtre (sil existe). On distingue comme prcdemment les cas o la cellule modifie est la premire et les autres
La suppression dune cellule de la liste se fait de la manire suivante (voir la figure 1.3) :
si la cellule est la premire de la liste, la nouvelle liste sera celle qui commence avec la seconde
cellule.
sinon la cellule a un prdcesseur ; pour liminer la cellule il faut la court-circuiter, en modifiant la variable suivant du prdcesseur pour quelle pointe vers la mme chose que la
variable suivant de la cellule.

pred
liste

ref

pred

ref

liste

e2

...

e1

...

ei

...

nouvelle liste
F IGURE 1.3 Suppression dune cellule de la liste
Le parcours de la liste la recherche de llment donn a une particularit : si la rfrence
sarrte sur la cellule qui contient llment, la suppression nest plus possible, car on na plus accs
au prdcesseur (dans les listes chanes on ne peut plus revenir en arrire).
La mthode utilise est alors de parcourir la liste avec deux rfrences :
une (elt) qui cherche la cellule liminer ;
une autre (precedent) qui se trouve toujours sur le prdcesseur de elt.
public void retirerPremiereOccurrence(int v) {
// On limine le problme de la liste vide
if (estVide())
return;
// Le but est de trouver llment qui prcde v...
// qui nexiste pas si v est la premire valeur=>
if (premier.getValeur() == v) {
premier= premier.getSuivant();
} else {
ElementListe precedent= premier;
ElementListe elt= premier.getSuivant();
while (elt != null && elt.getValeur() != v) {
precedent= elt;
elt= elt.getSuivant();
}
if (elt != null) {
// Llment a t trouv
// Plomberie:
precedent.setSuivant(elt.getSuivant());
}
}

c
NFA031 CNAM
2012

CHAPITRE 1. LISTES1.3.
CHANES
OPRATIONS SUR LES LISTES CHANES, VERSION ITRATIVE

1.3.4

Oprations avec parcours de liste - variante rcursive

Ces oprations sont bases sur une dcomposition rcursive de la liste en un premier lment et le
reste de la liste (voir la figure 1.4). Le cas le plus simple (condition darrt) est la liste avec une seule
cellule.

liste

premier reste

...

F IGURE 1.4 Dcomposition rcursive dune liste

Calcul rcursif de la longueur dune liste


La formule rcursive est :
longueur(listeElements) = 0
si listeElements est vide
1 + longueur(listeElements.suivant()) sinon
La fonction getLongueur scrit alors trs facilement, comme suit :
public int getLongueur() {
return getLongueurRec(premier);
}

private int getLongueurRec(ElementListe elt) {


if (elt == null)
return 0;
else
return 1 + getLongueurRec(elt.getSuivant());
}

Dans notre exemple, la n vraie z fonction rcursive est la seconde. Mais comme il nest pas pratique pour le programmeur qui utilise la classe dcrire
int l= maListe.getLongueurRec(maListe.getPremier());

on cache lappel rcursif en fournissant la mthode publique getLongueur() qui n amorce z lappel, le travail tant ensuite ralis par la mthode rcursive.
Vrification rcursive de lappartenance une liste
La formule rcursive est :
contient(listeElements, e) = false si listeElements == null
true si listeElements != null
et listeElements.valeur == e
contient(listeElements.suite, e) sinon
Remarquez que dans ce cas il y a deux conditions darrt : quand on trouve llment recherch
ou quand la liste est vide. La fonction rcursive contient scrit alors comme suit :
c
NFA031 CNAM
2012

1.3. OPRATIONS SUR LES LISTES CHANES, VERSIONCHAPITRE


ITRATIVE
1. LISTES CHANES

public boolean contient(int v) {


return contient(getPremier(), v);
}
private boolean contientRec(ElementListe elt, int v) {
// Si la liste est vide, elle ne contient pas v:
if (elt == null)
return false;
else if (elt.getValeur()== v)
// Sinon, si elle commence par v, alors elle le contient
return true;
else
// Sinon, elle contient v si la suite de la liste le contient
return contientRec(elt.getSuivant(), v);
}

Ici encore, la fonction rcursive est la seconde, la pemire tant une faade plus agrable dutilisation.
Concatnation rcursive de deux listes
public void concatener(Liste l) {
if (this.estVide()) {
this.premier= l.premier;
} else {
concatenerRec(premier,l.getPremier());
}
}
/**
*Mthode appele uniquement si l0 est non null.
*/
private void concatener(ElementListe l0, ElementListe l1) {
if (l0.getSuivant() == null) {
l0.setSuivant(l1);
} else {
concatenerRec(l0.getSuivant(), l1);
}
}

Suppression rcursive de la premire occurrence dun lment


Pour supprimer la premire occurrence dun lment, le principe est : La formule rcursive est :
supprimerPremier(l, e) =
null
si l est null
l.suite
si l.premier == e
ElementListe(l.premier, supprimerPremier(l.suite, e)) sinon
10

c
NFA031 CNAM
2012

CHAPITRE 1. LISTES CHANES

1.4. LISTES TRIES

Si le premier lment de la liste est celui recherch, le rsultat sera le reste de la liste. Sinon,
le rsultat sera une liste qui aura le mme premier lment, mais dans la suite de laquelle on aura
supprim la valeur cherche.
public void retirerPremiereOccurrence(int v) {
// On limine le problme de la liste vide
if (! estVide()) {
premier= retirerPremiereOccurrenceRec(premier, v);
}
}
public ElementListe retirerPremiereOccurrenceRec(ElementListe l, int v) {
if (l== null) {
return l;
} else if (l.getValeur() == v) {
return l.getSuivant();
} else {
return new ElementListe(l.getValeur(),
retirerPremiereOccurrenceRec(l.getSuivant(), v));
}
}

Remarque : Linconvnient de cette mthode est quon cre des copies de toutes les cellules qui ne
contiennent pas llment recherch. Pour viter cela, la dfinition doit mlanger calcul et effets
de bord, comme suit :
public ElementListe retirerPremiereOccurrenceRec(ElementListe l, int v) {
if (l== null) {
return l;
} else if (l.getValeur() == v) {
return l.getSuivant();
} else {
l.setSuivant(retirerPremiereOccurrenceRec(l.getSuivant(), v));
return l;
}
}

1.4

Listes tries

Nous nous intressons maintenant aux listes chanes dans lesquelles les lments respectent un
ordre croissant. Dans ce cas, les mthodes de recherche, dinsertion et de suppression sont diffrentes.
Lordre des lments permet darrter plus tt la recherche dun lment qui nexiste pas dans la liste.
Aussi, linsertion ne se fait plus en dbut de liste, mais la place qui prserve lordre des lments.
Nous utiliserons une classe ListeTriee qui est trs similaire la classe Liste, mais dans
laquelle on sintresse uniquement aux mthodes de recherche (contientTriee), dinsertion
(insertionTriee) et de suppression (suppressionTriee). Les autres mthodes sont identiques celles de la classe Liste.
class ListeTriee{
ElementListe premier;

c
NFA031 CNAM
2012

11

1.4. LISTES TRIES

CHAPITRE 1. LISTES CHANES

public ElementListe getPremier() {...}


public boolean contientTriee(int elem){...}
public void ajouterTriee(int elem){...}
public void retirerPremiereOccurrence(int elem){...}
}

1.4.1

Recherche dans une liste trie

La diffrence avec la mthode contient de Liste est que dans le parcours de la liste on peut
sarrter ds que la cellule courante contient un lment plus grand que celui recherch. Comme tous
les lments suivants vont en ordre croissant, ils seront galement plus grands que llment recherch.
Variante iterative :
public boolean contientTriee(int v) {
ElementListe elt = getPremier();
while (elt != null && elt.getValeur() < v) {
elt = elt.getSuivant();
}
return (elt != null && elt.getValeur() == v);
}

Variante rcursive :
public boolean contientTriee(int v) {
return contientTrieeRec(getPremier(), v);
}
private boolean contientTrieeRec(ElementListe elt, int v) {
if (elt == null) {
return false;
} else if (elt.getValeur() > v) {
return false;
} else if (elt.getValeur() == v) {
return true;
} else {
return contientTrieeRec(elt.getSuivant(), v);
}
}

1.4.2

Insertion dans une liste trie

Linsertion dun lment doit se faire la bonne place dans la liste. La bonne place est juste avant
la premire cellule qui contient un lment plus grand que celui insrer.
Variante iterative :
La figure 1.5 montre les deux cas dinsertion :
12

c
NFA031 CNAM
2012

CHAPITRE 1. LISTES CHANES

1.4. LISTES TRIES

en dbut de liste.
Elle est similaire alors lopration insertionDebut de la classe Liste
en milieu de liste.
La recherche de la position dinsertion se fait alors avec une mthode similaire celle utilise
pour la mthode suppressionPremier de la classe Liste, avec deux rfrences. Le prdcesseur doit tre modifi pour pointer vers la nouvelle cellule, tandis que celle-ci doit pointer
vers la cellule courante (ref).
pred

ref

liste
nouvelle liste

pred

ref

liste

e1

...

e1

...

ep

er

...

e
F IGURE 1.5 Insertion dans une liste trie
Dans la figure 1.5, droite, la rfrence ref peut ne pas pointer vers une cellule. Ceci arrive quand
llment insrer est plus grand que tous les lments de la liste. Dans ce cas, linsertion se fait
la fin de la liste, donc au moment de larrt de la recherche, ref est nulle et pred est sur la dernire
cellule de la liste. Ce cas est identique celui prsent dans la figure 1.5, la variable suivant de
la nouvelle cellule on donne tout simplement la valeur de ref.
public void ajouterTriee(int v) {
if (estVide()) {
premier = new ElementListe(v);
} else if (getPremier().getValeur() >= v) {
// Insertion au dbut de la liste.
premier = new ElementListe(v, premier);
} else {
// On veut chercher llment qui prcde notre valeur
// Le problme est que nous ne savons que nous avons
// llment prcdent que parce que le suivant
// est strictement plus grand que v.
ElementListe precedent = getPremier(); // Initialisation correcte car
// getPremier().getValeur() < v.
ElementListe elt = getPremier().getSuivant();
while (elt != null && elt.getValeur() < v) {
precedent = elt;
elt = elt.getSuivant();
}
precedent.setSuivant(new ElementListe(v, elt));
}
}

Variante rcursive :
Nous utilisons le mme schma de dcomposition rcursive de la liste, en un premier lment
(premier) et un reste de la liste (reste). Linsertion rcursive suit le schma suivant :
liste.insertionTriee(e) =
ListeTriee(e, liste)
c
NFA031 CNAM
2012

si e<=premier
13

1.4. LISTES TRIES

CHAPITRE 1. LISTES CHANES

liste aprs reste=ListeTriee(e, null)


si e>premier et reste==null
liste aprs reste=reste.insertionTriee(e) si e>premier et reste!=null
Si llment insrer est plus petit ou gal premier, linsertion se fera en tte de liste. Sinon,
linsertion se fera rcursivement dans le reste. Si reste est vide, alors reste sera remplac par la nouvelle
cellule insrer. Si reste nest pas vide, linsertion se fait rcursivement dans reste et le rsultat
remplace lancien reste.
public void ajouterTriee(int v) {
premier= ajouterTrieeRec(premier,v);
}
private ElementListe ajouterTrieeRec(ElementListe elt, int v) {
if (elt == null) {
return new ElementListe(v);
} else if (elt.getValeur() > v) {
return new ElementListe(v, elt);
} else {
ElementListe e= ajouterTrieeRec(elt.getSuivant(), v);
elt.setSuivant(e);
return elt;
}
}

1.4.3

Suppression dans une liste trie

La suppression de la premire occurrence dun lment dans une liste trie est assez similaire
la suppression dans une liste non trie. La seule chose qui change est la recherche de la cellule
supprimer, qui bnficie du tri des valeurs. Aussi, si plusieurs occurrences de llment existent, elles
sont forcment lune la suite de lautre cause du tri. Il serait donc plus simple dliminer toutes les
occurrences de llment que dans le cas des listes non tries. Nous nous limiterons cependant ici la
suppression de la premire occurrence seulement.
Variante iterative :
Par rapport la mthode suppressionPremier de la classe Liste, ici le parcours de la
liste la recherche de llment ne se fait que tant que ref pointe une valeur plus petite que celui-ci.
Une fois le parcours arrt, la seule diffrence est quil faut vrifier que ref pointe vraiment la valeur
recherche.
public void retirerPremiereOccurrence(int v) {
// On limine le problme de la liste vide
if (estVide())
return;
// Le but est de trouver llment qui prcde v...
// qui nexiste pas si v est la premire valeur=>
if (premier.getValeur() == v) {
premier = premier.getSuivant();
} else {
ElementListe precedent = null;
ElementListe elt = premier;
while (elt != null && elt.getValeur() < v) {

14

c
NFA031 CNAM
2012

CHAPITRE 1. LISTES CHANES


1.5. UN EXEMPLE DE PROGRAMME QUI UTILISE LES LISTES
precedent = elt;
elt = elt.getSuivant();
}
if (elt != null && elt.getValeur() == v) {
// Llment a t trouv
// Plomberie:
precedent.setSuivant(elt.getSuivant());
}
}
}

Variante rcursive :
Par rapport la variante rcursive de la mthode suppressionPremier de la classe Liste,
une nouvelle condition darrt est rajoute :
quand llment liminer est plus petit que premier, il nexiste srement pas dans la liste et celle-ci
est retourne non modifie.
public void retirerPremiereOccurrence(int v) {
premier= retirerPremiereOccurrenceRec(premier, v);
}
private ElementListe retirerPremiereOccurrenceRec(ElementListe elt, int v) {
if (elt == null) {
return null;
} else if (v == elt.getValeur()) {
return elt.getSuivant();
} else if (v < elt.getValeur()) {
return elt;
} else {
elt.setSuivant(retirerPremiereOccurrenceRec(elt.getSuivant(),v));
return elt;
}
}

1.5

Un exemple de programme qui utilise les listes

Considrons un exemple simple de programme qui manipule des listes chanes en utilisant la
classe Liste.
Le programme lit une suite de nombres entiers termine par la valeur 0 et construit une liste avec
ces entiers (sauf le 0 final). La liste doit garder les lments dans lordre dans lequel ils sont introduits.
Egalement, une valeur ne doit tre stocke quune seule fois dans la liste.
Le programme lit ensuite une autre suite de valeurs, galement termine par un 0, avec lesquelles
il construit une autre liste, sans se soucier de lordre des lments. Les lments de cette seconde liste
devront tre limins de la liste initiale.
A la fin, le programme affiche ce qui reste de la premire liste.
Remarque : Pour garder les lments dans lordre dintroduction, linsertion dun nouvel lment
doit se faire en fin de liste. La mthode ajouterAuDebut ne convient donc pas. On pourrait
se dbrouiller avec la mthode concatener, mais comme lopration est frquemment utile,
on suppose crite la mthode ajouterALaFin.
c
NFA031 CNAM
2012

15

1.5. UN EXEMPLE DE PROGRAMME QUI UTILISE LES LISTES


CHAPITRE 1. LISTES CHANES
Remarque : Pour quun lment soit stock une seule fois dans la liste, il faut dabord vrifier sil
ny est pas dj, laide de la mthode contient.
Voici le programme qui ralise ces actions :
public class ExempleListes{
public static void main(String[] args){
//1. Creation premiere liste
Terminal.ecrireStringln("Entrez les valeurs terminees par un 0 :");
Liste liste = new Liste(); //liste a construire
do{
int val = Terminal.lireInt();
if(val==0) break;
if (! liste.contient(val))
liste.ajouterALaFin(val);
} while(true);
//2. Creation seconde liste
Terminal.ecrireStringln("Valeurs a eliminer (terminees par un 0) :");
Liste liste2 = new Liste();
do{
int val = Terminal.lireInt();
if(val==0) break;
liste2.ajouterAuDebut(val);
} while(true);
//3. Elimination des lments de la premiere liste
for(ElementListe ref = liste2.getPremier(); ref != null; ref = ref.getSuivant()){
if(liste.estVide()) break; //plus rien a eliminer
liste.retirerPremiereOccurrence(ref.getValeur());
}
//4. Affichage liste restante
Terminal.ecrireStringln("Valeurs restantes :");
for(ElementListe ref = liste.getPremier(); ref != null; ref = ref.getSuivant())
Terminal.ecrireString(" " + ref.getValeur());
Terminal.sautDeLigne();
}
}

16

c
NFA031 CNAM
2012

Vous aimerez peut-être aussi