Un exemple simple fera mieux comprendre le système et son intérêt. La structure de liste chaînée est sans doute déjà connue du lecteur. Il sagit dune suite de noeuds, contenant chacun un pointeur vers un autre noeud et un élément dinformation dun type quelconque (nommé element
dans la suite). Lintérêt de cet agencement réside dans sa fluidité ; il est très facile par exemple de supprimer ou dajouter un élément.
Voici un exemple dimplantation dune structure noeud
, brique de base dune liste chaînée, sans méthode pour le moment :
typedef long element; // (par exemple) struct noeud { noeud *suivt; // le suivant dans la liste element elm; // information contenue };
Une liste chaînée est cependant fragile. Si par erreur on modifie lun des pointeurs, la liste sera coupée, les informations perdues et le programme complètement égaré.
Nous allons donc blinder notre structure afin de limiter les risques :
struct noeud { private : noeud *suivt; // le suivant dans la liste element elm; // information contenue public : noeud *suivant(void) { return suivt; } element &contenu(void) { return elm; } };
Nos deux champs sont à présent privés, de sorte que lécriture suivante :
noeud no;no.suivt = 0;
provoque une erreur Error : 'noeud::suivt' is not accessible, 'noeud::suivt' nest pas accessible.
On ne peut plus dans notre exemple que lire le contenu (le champ elm
) du noeud, ou connaître le suivant de la liste, à laide des méthodes. Cest évidemment un peu excessif, car il nest dès lors plus possible de modifier la liste. Nous allons ajouter une fonction qui insère un élément dans la liste, et une autre qui le supprime :
struct noeud { private : noeud *suivt; // le suivant dans la liste element elm; // information contenue public : noeud *suivant(void) { return suivt; } element &contenu(void) { return elm; } noeud* supprime_svt(void); noeud* insere(element e); };noeud* noeud::supprime_svt(void);// supprime le noeud suivant et // renvoie un pointeur sur le nouveau suivant { if (!suivt) return 0; // pas de suivant noeud *s = suivt; suivt = s->suivt; delete s; return suivt;}noeud* noeud::insere(element e)// insère un nouvel élément de valeur e derrière this.// renvoie 0 si plus de mémoire, sinon suivt.{ noeud *nouveau = new noeud; if (!nouveau) return 0; // plus de mémoire nouveau->suivt = suivt; nouveau->elm = e; return suivt = nouveau;}
Contrairement aux précédentes, ces fonctions nont pas été écrites en ligne, car elles sont un peu plus complexes (mais on aurait tout de même pu le faire, elles ne contiennent pas de boucle).
Exercice 6.1 | Quel fondement essentiel manque dans notre liste chaînée, qui la rend inutilisable ? Comment résoudre le problème (un meilleur moyen est donné plus loin dans le chapitre) ? |
Voir solution |
À part la réserve mentionnée dans lexercice, notre type de base pour liste chaînée est assez au point, et évitera bien des erreurs. Nous ferons mieux par la suite, mais voyons encore quelques notations.
Précédent | Sommaire | Suivant |