Beruflich Dokumente
Kultur Dokumente
Par lexou
www.openclassrooms.com
2/19
Sommaire
Sommaire ........................................................................................................................................... 2
Les listes chanes ............................................................................................................................ 3
Gnralits sur les listes chaines ................................................................................................................................... 3
Dclaration en C d'une liste chaine ................................................................................................................................. 5
Manipuler les listes chaines (1/2) .................................................................................................................................... 6
Ajouter un lment ...................................................................................................................................................................................................... 6
www.openclassrooms.com
Sommaire
3/19
Par
lexou
Il s'adresse toute personne ayant suivi les cours de M@teo jusqu'aux pointeurs. Ce tutoriel accompagn des exercices que je
vous proposerai sont mon avis un excellent entranement, en ce qui concerne les pointeurs, entre autres, mais fera appel
toutes vos connaissances du langage C.
Le but de ce tutoriel est de vous initier aux listes chanes, une autre faon d'implmenter un conteneur, la plus courante tant
les tableaux. A la fin de ce cours, vous serez capables de coder votre propre bibliothque permettant la cration et la
manipulation de listes simplement chanes. Les listes doublement chaines seront introduites pour terminer afin que vous
puissiez amliorer votre bibliothque.
www.openclassrooms.com
4/19
Vous avez sur ce schma la reprsentation que l'on pourrait faire d'un tableau et d'une liste chane. Chacune de ces
reprsentations possde ses avantages et inconvnients. C'est lors de l'criture de votre programme que vous devez vous poser
la question de savoir laquelle des deux mthodes est la plus intressante.
Dans un tableau, la taille est connue, l'adresse du premier lment aussi. Lorsque vous dclarez un tableau, la variable
contiendra l'adresse du premier lment de votre tableau.
Comme le stockage est contigu, et la taille de chacun des lments connue, il est possible d'atteindre directement la case i
d'un tableau.
Pour dclarer un tableau, il faut connatre sa taille.
Pour supprimer ou ajouter un lment un tableau, il faut crer un nouveau tableau et supprimer l'ancien. Ce n'est en
gnral pas visible par l'utilisateur, mais c'est ce que realloc va souvent faire. L'adresse du premier lment d'un
tableau peut changer aprs un realloc, ce qui est tout fait logique puisque realloc n'aura pas forcement la
possibilit de trouver en mmoire la place ncessaire et contigu pour allouer votre nouveau tableau. realloc va donc
chercher une place suffisante, recopier votre tableau, et supprimer l'ancien.
Dans une liste chane, la taille est inconnue au dpart, la liste peut avoir autant d'lments que votre mmoire le permet.
Il est en revanche impossible d'accder directement l'lment i de la liste chaine.
Pour ce faire, il vous faudra traverser les i-1 lments prcdents de la liste.
Pour dclarer une liste chane, il suffit de crer le pointeur qui va pointer sur le premier lment de votre liste chane,
aucune taille n'est donc spcifier.
Il est possible d'ajouter, de supprimer, d'intervertir des lments d'une liste chane sans avoir recrer la liste en entier,
mais en manipulant simplement leurs pointeurs.
www.openclassrooms.com
5/19
Comme vous vous en doutez certainement maintenant, la liste chane est un type structur. Nous en avons termin avec ces
quelques gnralits, nous allons pouvoir passer la dfinition d'une structure de donnes nous permettant de crer cette
fameuse liste !
Vous pouvez essayer d'imaginer quoi va ressembler la structure liste_chainee : si vous avez compris le principe,
vous en tes capables. Je vous invite donc crire sur un papier vos ides que vous pourrez ensuite comparer au
rsultat que je vais fournir un peu plus bas !
On cre le type element qui est une structure contenant un entier (val) et un pointeur sur lment (nxt), qui contiendra l'adresse
de l'lment suivant. Ensuite, il nous faut crer le type llist (pour linked list = liste chane) qui est en fait un pointeur sur le type
element. Lorsque nous allons dclarer la liste chane, nous devrons dclarer un pointeur sur element, l'initialiser NULL, pour
pouvoir ensuite allouer le premier lment. N'oubliez pas d'inclure stdlib.h afin de pouvoir utiliser la macro NULL. Comme vous
allez le constater, nous avons juste cre le type llist afin de simplifier la dclaration.
Voil comment dclarer une liste chane (vide pour l'instant) :
Code : C
#include <stdlib.h>
www.openclassrooms.com
6/19
return 0;
Il est important de toujours initialiser la liste chane NULL. Le cas chant, elle sera considre comme contenant au
moins un lment. C'est une erreur frquente. A garder en mmoire donc. De manire gnrale, il est plus sage de
toujours initialiser vos pointeurs.
Ajouter un lment
Lorsque nous voulons ajouter un lment dans une liste chane, il faut savoir o l'insrer. Les deux ajouts gnriques des listes
chanes sont les ajouts en tte, et les ajouts en fin de liste. Nous allons tudier ces deux moyens d'ajouter un lment une
liste.
Ajouter en tte
Lors d'un ajout en tte, nous allons crer un lment, lui assigner la valeur que l'on veut ajouter, puis pour terminer, raccorder cet
lment la liste passe en paramtre. Lors d'un ajout en tte, on devra donc assigner nxt l'adresse du premier lment de la
liste pass en paramtre. Visualisons tout ceci sur un schma :
Code : C
www.openclassrooms.com
7/19
C'est l'ajout le plus simple des deux. Il suffit de crer un nouvel lment puis de le relier au dbut de la liste originale. Si l'original
est , (vide) c'est NULL qui sera assigne au champ nxt du nouvel element. La liste contiendra dans ce cas-l un seul lment.
Code : C
llist ajouterEnFin(llist liste, int valeur)
{
/* On cre un nouvel lment */
element* nouvelElement = malloc(sizeof(element));
/* On assigne la valeur au nouvel lment */
nouvelElement->val = valeur;
/* On ajoute en fin, donc aucun lment ne va suivre */
nouvelElement->nxt = NULL;
if(liste == NULL)
{
/* Si la liste est vide il suffit de renvoyer l'lment
cr */
return nouvelElement;
}
else
{
www.openclassrooms.com
8/19
Comme vous pouvez le constater, nous nous dplaons le long de la liste chane grce au pointeur temp. Si l'lment point par
temp n'est pas le dernier (temp->nxt != NULL), on avance d'un cran (temp = temp->nxt) en assignant temp l'adresse de l'lment
suivant. Une fois que l'on est au dernier lment, il ne reste plus qu' le relier au nouvel lment.
Si vous pensez avoir bien saisi ces deux fonctions, je vous invite passer la partie suivante, dans laquelle je vais vous
proposer quelques exercices. Le premier sera fondamental puisqu'il nous permettra d'afficher le contenu d'une liste chane.
Exercices (1/2)
Exercice n1
Vous allez maintenant pouvoir vous tester. Votre mission, si vous l'acceptez, est de coder la fonction afficherListe. Vous devrez
parcourir la liste jusqu'au bout et afficher toutes les valeurs qu'elle contient. Voici son prototype :
Code : C
void afficherListe(llist liste);
Correction
Secret (cliquez pour afficher)
Code : C
void afficherListe(llist liste)
{
element *tmp = liste;
/* Tant que l'on n'est pas au bout de la liste */
while(tmp != NULL)
{
/* On affiche */
printf("%d ", tmp->val);
/* On avance d'une case */
tmp = tmp->nxt;
}
}
Alors ? Qu'est ce que a donne ? Si vous avez russi ce premier exercice, vous tes sur la bonne voie.
Quelques explications pour ceux qui ont eu quelques difficults : la seule chose faire est de se dplacer le long de la liste
chane grce au pointeur tmp. Si ce pointeur tmp pointe sur NULL, c'est que l'on a atteint le bout de la chane, sinon c'est
que nous sommes sur un lment dont il faut afficher la valeur.
Exercice n2
www.openclassrooms.com
9/19
Un deuxime exercice utilisant trois fonctions que nous avons vues jusqu' prsent :
ajouterEnTete
ajouterEnFin
afficherListe
Vous devez crire le main permettant de remplir et afficher la liste chane ci-dessous. Vous ne devrez utiliser qu'une seule boucle
for.
Code : Console
10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10
Aucune autre directive pour cet exercice qui ncessite peut-tre un peu de logique, mais question technique vous devriez tre au
point.
Correction
Secret (cliquez pour afficher)
Code : C
int main(int argc, char **argv)
{
llist ma_liste = NULL;
int i;
for(i=1;i<=10;i++)
{
ma_liste = ajouterEnTete(ma_liste, i);
ma_liste = ajouterEnFin(ma_liste, i);
}
afficherListe(ma_liste);
supprimerListe(ma_liste); // Libre les ressources, nous
verrons cette fonction plus tard.
}
return 0;
Une simple boucle suffit. Au dbut, la liste est vide. Vous ajoutez un premier lment gal 1, puis un deuxime 1. Aprs un
premier passage, votre liste contient deux lments 1. Au deuxime passage, nous allons ajouter un lment 2 en tte, puis un
lment 2 en fin pour obtenir 2 1 1 2. Il suffit alors de rpter l'opration dix fois.
Exercice n3
L'exercice suivant est le plus simple des trois, mais il me faut vous le montrer. crivez une fonction qui renvoie 1 si la liste est
vide, et 0 si elle contient au moins un lment. Son prototype est le suivant :
Code : C
int estVide(llist liste);
Vous vous demandez srement l'intrt d'crire une telle fonction... eh bien quand vous codez une bibliothque, le mieux est de
"masquer" le fonctionnement interne de vos codes. L'utilisateur n'est pas cens savoir qu'une liste vide sera gale NULL, ni
mme que le type llist est un pointeur. Lui, il dclare une llist sans savoir comment elle est cre, puis l'utilise (ajoute ou supprime
www.openclassrooms.com
10/19
des lments, trie sa liste, etc...) grce aux fonctions de la bibliothque. Dans certains cas, il lui faudra tester si la liste est vide, il
utilisera par exemple :
Code : C
if(estVide(ma_liste))
{
printf("La liste est vide");
}
else
{
afficherListe(ma_liste);
}
Correction
Secret (cliquez pour afficher)
Code : C
int estVide(lliste liste)
{
if(liste == NULL)
{
return 1;
}
else
{
return 0;
}
}
Ou bien, en condens :
Code : C
int estVide(llist liste)
{
return (liste == NULL)? 1 : 0;
}
Nous voil au bout de cette premire srie d'exercices. Dans la section suivante, nous allons voir plein de fonctions plus
complexes permettant de manipuler nos listes chanes !
www.openclassrooms.com
11/19
Prts ? On y va !
www.openclassrooms.com
12/19
/* On dplace tmp (mais ptmp garde l'ancienne valeur de tmp
tmp = tmp->nxt;
}
/* A la sortie de la boucle, tmp pointe sur le dernier lment,
et ptmp sur
l'avant-dernier. On indique que l'avant-dernier devient la fin de
la liste
et on supprime le dernier lment */
ptmp->nxt = NULL;
free(tmp);
return liste;
}
www.openclassrooms.com
13/19
return 0;
www.openclassrooms.com
14/19
www.openclassrooms.com
15/19
Exercices (2/2)
Exercice n1
Voil... Maintenant, vous tes des as en matire de liste chanes, j'en suis sr. Je vous propose donc quelques exercices. Le
premier sera de coder de manire itrative la fonction nombreElements dont je vous rappelle le prototype :
Code : C
int nombreElements(llist liste);
C'est un exercice qui ne devrait pas vous poser de problmes : bonne chance.
Secret (cliquez pour afficher)
Code : C
int nombreElements(llist liste)
{
int nb = 0;
element* tmp = liste;
/* On parcours la liste */
while(tmp != NULL)
{
/* On incrmente */
nb++;
tmp = tmp->nxt;
}
/* On retourne le nombre d'lments parcourus */
return nb;
C'est aussi simple que a. On parcourt simplement la liste tant que l'on n'est pas arriv au bout, et on incrmente le compteur
nb que l'on renvoie pour finir.
Exercice n2
Nous allons maintenant crire une fonction permettant d'effacer compltement une liste chane de la mmoire. Je vous propose
www.openclassrooms.com
16/19
d'crire avec un algorithme itratif dans un premier temps, puis une seconde fois grce un algorithme rcursif. Dans le premier
cas, vous devez parcourir la liste, stocker l'lment suivant, effacer l'lment courant et avancer d'une case. A la fin la liste est
vide, nous retournerons NULL.
Secret (cliquez pour afficher)
Code : C
llist effacerListe(llist liste)
{
element* tmp = liste;
element* tmpnxt;
/* Tant que l'on n'est pas au bout
while(tmp != NULL)
{
/* On stocke l'lment suivant
avancer */
tmpnxt = tmp->nxt;
/* On efface l'lment courant
free(tmp);
/* On avance d'une case */
tmp = tmpnxt;
}
/* La liste est vide : on retourne
return NULL;
}
de la liste */
pour pouvoir ensuite
*/
NULL */
Code : C
llist effacerListe(llist liste)
{
if(liste == NULL)
{
/* Si la liste est vide, il n'y a rien effacer, on
retourne
une liste vide i.e. NULL */
return NULL;
}
else
{
/* Sinon, on efface le premier lment et on retourne le
reste de la
liste efface */
element *tmp;
tmp = liste->nxt;
free(liste);
return effacerListe(tmp);
}
}
Et voil : vous en savez maintenant un peu plus sur ce que sont les listes chanes. Vous pourrez amliorer ceci en utilisant les
listes doublement chanes, qui sont en fait une liste d'lments qui pointent la fois sur l'lment suivant, mais aussi sur
l'lment prcdent, ce qui vous permet de revenir en arrire plus facilement qu'avec les listes simplement chanes. Vous pouvez
complter votre bibliothque avec des fonctions de tri, de recherche de minimum, de maximum et bien d'autre choses...
Passons maintenant un petit QCM, afin de vrifier que vous avez tout saisi !
Q.C.M.
Le premier QCM de ce cours vous est offert en libre accs.
Pour accder aux suivants
www.openclassrooms.com
17/19
Connectez-vous Inscrivez-vous
Une erreur s'est glisse dans le code suivant :
Code : C
typedef struct element element;
struct element
{
int val;
struct element nxt;
};
Il manque un typedef
Il manque une toile
Le code est juste
Rien du tout
a ne compile pas : tu as mis element* la place de llist pour dclarer ma_liste
Une erreur de segmentation
Correction !
Statistiques de rponses au Q CM
Eh bien il semblerait que vous tes au point. Comme vous avez pu le constater, le choix d'utiliser ou non les listes chanes est
fait lors de l'implmentation de votre algorithme dans un langage. Vous devrez toujours faire des compromis.
J'avais parl d'introduire les listes doublement chanes, ce que je vais faire maintenant pour vous permettre d'aller plus loin.
L'ide est la suivante : un lment ne va plus se composer d'une valeur et d'une adresse, mais d'une valeur et de deux adresses :
l'adresse de l'lment suivant mais aussi l'adresse de l'lment prcdent. On pourra tirer avantage de cette spcificit pour lire
des listes l'envers. Avoir l'adresse de l'lment prcdent peut simplifier les algorithmes de vos fonctions, mais tout aussi bien
les compliquer car c'est maintenant deux pointeurs qu'il faut grer lors d'un ajout ou d'une suppression.
Nous sommes loin d'avoir cod une bibliothque complte, mais vos connaissances vous permettent maintenant de continuer
seuls et d'implmenter toutes sortes de fonctions.
Merci d'avoir lu ce tutoriel jusqu'au bout. Si une ou plusieurs erreurs s'y sont glisses (ce n'est pas exclu), prvenez-moi par MP.
Remerciements Nicolas et Mleg pour avoir vrifi, test ce tutoriel et permis de ce fait sa parution.
Je sais que le sujet des listes chaines est souvent abord lors de l'entre dans les tudes suprieures, aussi je
serais ravis d'apprendre qu'un professeur vous a redirig sur mon tutoriel, si tel est le cas n'hsitez pas me le faire
savoir par message !
A bientt !
www.openclassrooms.com
18/19
Partager
www.openclassrooms.com