Vous êtes sur la page 1sur 20

INTRODUCTION

Cette article a pour but la comprhension des listes simplement chanes. L'implmentation en fonction des besoins et des performances vous appartient. Les listes chanes peuvent tre utilises quand plusieurs oprations d'insertion/suppression d'lments sont ncessaires.

Dfinition
Les listes chanes sont des structures de donnes semblables aux tableaux sauf que l'accs un lment ne se fait pas par index mais l'aide d'un pointeur. L'allocation de la mmoire est faite au moment de l'excution. Dans une liste les lments sont contigus en ce qui concerne l'enchanement.

En revanche, par rapport aux tableaux o les lments sont contigus dans la mmoire, les lments d'une liste sont parpills dans la mmoire. La liaison entre les lments se fait grce un pointeur. En ralit, dans la mmoire la reprsentation est alatoire en fonction de l'espace allou. Le pointeur suivant du dernier lment doit pointer vers NULL (la fin de la liste). Pour accder un lment la liste est parcourue en commenant avec la tte, le pointeur suivant permettant le dplacement vers le prochain lment. Le dplacement se fait dans une seule direction, du premier vers le dernier lment. Si vous voulez vous dplacer dans les deux directions (en avant/en arrire) utilisez les listes doublement chanes.

La construction du prototype d'un lment de la liste


Pour dfinir un lment de la liste le type struct sera utilis. L'lment de la liste contiendra un champ donnee et un pointeur suivant. Le pointeur suivant doit tre du mme type que l'lment, sinon il ne pourra pas pointer vers l'lment. Le pointeur "suivant" permettra l'accs vers le prochain lment.

typedef struct ElementListe { char }Element; Pour avoir le contrle de la liste il est prfrable de sauvegarder certains lments : le premier lment, le dernier lment, le nombre d'lments. *donnee; struct ElementListe *suivant;

Pour raliser cela une autre structure sera utilise (ce n'est pas obligatoire, des variables peuvent tre utilises). Voici sa composition: typedef struct ListeRepere { Element *debut; Element *fin; int taille; }Liste; Le pointeur debut contiendra l'adresse du premier lment de la liste. Le pointeur fin contiendra l'adresse du dernier lment de la liste. La variable taille contient le nombre d'lments. Quelque soit la position dans la liste, les pointeurs debut et fin pointent toujours respectivement vers le 1er et le dernier lment. Le champ taille contiendra le nombre d'lments de la liste quelque soit l'opration effectue sur la liste.

Oprations sur les listes chanes


Pour l'insertion ainsi que pour la suppression, une seule fonction est largement suffisante si elle est bien conue en fonction des besoins. Toutefois je vous rappelle que cet article est purement didactique. C'est la raison pour laquelle j'ai crit une fonction pour chaque opration d'insertion et de suppression.

Initialisation
Prototype de la fonction : void initialisation (Liste *liste); Cette opration doit tre faite avant toute autre opration sur la liste. Elle initialise le pointeur debut et le pointeur fin avec le pointeur NULL, et la taille avec la valeur

0. La fonction void initialisation (Liste *liste){ liste->debut = NULL; liste->fin = NULL; taille = 0; }

Insertion d'un lment dans la liste


Voici l'algorithme d'insertion et de sauvegarde des lments : dclaration d'lment(s) insrer allocation de la mmoire pour le nouvel lment remplir le contenu du champ de donnes mettre jour les pointeurs vers le 1er et le dernier lment si ncessaire. Cas particulier : dans une liste avec un seul lment, le 1er est en mme temps le dernier. mettre jour la taille de la liste

Pour ajouter un lment dans la liste il y a plusieurs situations : 1. Insertion dans une liste vide 2. Insertion au dbut de la liste 3. Insertion la fin de la liste 4. Insertion ailleurs dans la liste

Insertion dans une liste vide


Prototype de la fonction : int ins_dans_liste_vide (Liste *liste, char *donnee); La fonction renvoie -1 en cas d'chec sinon elle renvoie 0. tapes : allocation de la mmoire pour le nouvel lment remplir le champ de donnes du nouvel lment

le pointeur suivant du nouvel lment pointera vers NULL (vu que l'insertion est faite dans une liste vide on utilise l'adresse du pointeur debut qui vaut NULL) les pointeurs debut et fin pointeront vers le nouvel lment la taille est mise jour

La fonction /* insertion dans une liste vide */ int ins_dans_liste_vide (Liste * liste, char *donnee){ Element *nouveau_element; if ((nouveau_element = (Element *) malloc (sizeof (Element))) == NULL) return -1; if ((nouveau_element->donnee = (char *) malloc (50 * sizeof (char))) == NULL) return -1; strcpy (nouveau_element->donnee, donnee); nouveau_element->suivant = NULL; liste->debut = nouveau_element; liste->fin = nouveau_element; liste->taille++; return 0; }

Insertion au dbut de la liste


Prototype de la fonction : int ins_debut_liste (Liste *liste,char *donnee);

La fonction renvoie -1 en cas d'chec sinon elle renvoie 0.

tapes: allocation de la mmoire pour le nouvel lment remplir le champ de donnes du nouvel lment le pointeur suivant du nouvel lment pointe vers le 1er lment le pointeur debut pointe vers le nouvel lment le pointeur fin ne change pas la taille est incrmente

La fonction /* insertion au dbut de la liste */ int ins_debut_liste (Liste * liste, char *donnee){ Element *nouveau_element; if ((nouveau_element = (Element *) malloc (sizeof (Element))) == NULL) return -1; if ((nouveau_element->donnee = (char *) malloc (50 * sizeof (char))) == NULL) return -1; strcpy (nouveau_element->donnee, donnee); nouveau_element->suivant = liste->debut; liste->debut = nouveau_element;

liste->taille++; return 0; }

Insertion la fin de la liste


Prototype de la fonction : int ins_fin_liste (Liste *liste, Element *courant, char *donnee); La fonction renvoie -1 en cas d'chec sinon elle renvoie 0. tapes: allocation de la mmoire pour le nouvel lment remplir le champ de donnes du nouvel lment le pointeur suivant du dernier lment pointe vers le nouvel lment le pointeur fin pointe vers le nouvel lment le pointeur debut ne change pas la taille est incrmente

La fonction /*insertion la fin de la liste */ int ins_fin_liste (Liste * liste, Element * courant, char *donnee){ Element *nouveau_element; if ((nouveau_element = (Element *) malloc (sizeof (Element))) == NULL)

return -1; if ((nouveau_element->donnee = (char *) malloc (50 * sizeof (char))) == NULL) return -1; strcpy (nouveau_element->donnee, donnee); courant->suivant = nouveau_element; nouveau_element->suivant = NULL; liste->fin = nouveau_element; liste->taille++; return 0; }

Insertion ailleurs dans la liste


Prototype de la fonction : int ins_liste (Liste *liste, char *donnee,int pos); La fonction renvoie -1 en cas d'chec sinon elle renvoie 0. L'insertion s'effectuera aprs une certaine position passe en argument la fonction. Si la position indique ne doit pas tre le dernier lment. Dans ce cas il faut utiliser la fonction d'insertion la fin de la liste. tapes: allocation de la mmoire pour le nouvel lment remplir le champ de donnes du nouvel lment choisir une position dans la liste (l'insertion se fera aprs la position choisie) le pointeur suivant du nouvel lment pointe vers l'adresse sur laquelle pointe le pointeur suivant d'lment courant. (cette explication est un peu tordue, mais l'image vous claira ;-) le pointeur suivant du l'lment courant pointe vers le nouvel lment les pointeurs debut et fin ne change pas la taille est incrmente d'une unit

La fonction /* insertion la position demande */ int ins_liste (Liste * liste, char *donnee, int pos){ if (liste->taille < 2) return -1; if (pos < 1 || pos >= liste->taille) return -1; Element *courant; Element *nouveau_element; int i; if ((nouveau_element = (Element *) malloc (sizeof (Element))) == NULL) return -1; if ((nouveau_element->donnee = (char *) malloc (50 * sizeof (char))) == NULL) return -1; courant = liste->debut; for (i = 1; i < pos; ++i) courant = courant->suivant;

if (courant->suivant == NULL) return -1; strcpy (nouveau_element->donnee, donnee); nouveau_element->suivant = courant->suivant; courant->suivant = nouveau_element; liste->taille++; return 0; }

Suppression d'un lment dans la liste


Voici l'algorithme de suppression d'un lment de la liste : utilisation d'un pointeur temporaire pour sauvegarder l'adresse d'lments supprimer l'lment supprimer se trouve aprs l'lment courant

Faire pointer le pointeur suivant de l'lment courant vers l'adresse du pointeur suivant de l'lment supprimer librer la mmoire occupe par l'lment supprim mettre jour la taille de la liste

Pour supprimer un lment dans la liste il y a plusieurs situations : 1. Suppression au dbut de la liste 2. Suppression ailleurs dans la liste

Suppression au dbut de la liste


Prototype de la fonction: int supp_debut (Liste *liste); La fonction renvoie -1 en cas d'chec sinon elle renvoie 0.

tapes: le pointeur supp_elem contiendra l'adresse du 1er lment le pointeur debut pointera vers le 2me lment la taille de la liste sera dcrmente d'un lment

La fonction /* suppression au dbut de la liste */ int supp_debut (Liste * liste){ if (liste->taille == 0) return -1; Element *supp_element; supp_element = liste->debut; liste->debut = liste->debut->suivant; if (liste->taille == 1) liste->fin = NULL; free (supp_element->donnee); free (supp_element); liste->taille--; return 0; }

Suppression ailleurs dans la liste


Prototype de la fonction: int supp_dans_liste (Liste *liste, int pos); La fonction renvoie -1 en cas d'chec sinon elle renvoie 0.

tapes: le pointeur supp_elem contiendra l'adresse vers laquelle pointe le pointeur suivant d'lment courant le pointeur suivant de l'lment courant pointera vers l'lment sur lequel pointe le pointeur suivant de l'lment qui suit l'lment courant dans la liste Si l'lment courant est l'avant dernier lment, le pointeur fin doit tre mis jour la taille de la liste sera dcrmente d'un lment

La fonction /* supprimer un element aprs la position demande */ int supp_dans_liste (Liste * liste, int pos){ if (liste->taille <= 1 || pos < 1 || pos >= liste->taille) return -1; int i; Element *courant; Element *supp_element; courant = liste->debut; for (i = 1; i < pos; ++i) courant = courant->suivant; supp_element = courant->suivant; courant->suivant = courant->suivant->suivant; if(courant->suivant == NULL) liste->fin = courant; free (supp_element->donnee); free (supp_element); liste->taille--; return 0; }

Affichage de la liste
Pour afficher la liste entire il faut se positionner au dbut de la liste (le pointeur debut le permettra). Ensuite en utilisant le pointeur suivant de chaque lment la liste est parcourue du 1er vers le dernier lment. La condition d'arrt est donne par le pointeur suivant du dernier lment qui vaut NULL. La fonction /* affichage de la liste */ void affiche (Liste * liste){ Element *courant; courant = liste->debut; while (courant != NULL){ printf ("%p - %s\n", courant, courant->donnee); courant = courant->suivant; } }

Destruction de la liste
Pour dtruire la liste entire, j'ai utilis la suppression au dbut de la liste tant que la taille est plus grande que zro. La fonction /* dtruire la liste */ void detruire (Liste * liste){ while (liste->taille > 0) supp_debut (liste); }

Exemple complet
liste.h
/* ---------- liste.h ----------- */ typedef struct ElementListe { char *donnee; struct ElementListe *suivant; } Element; typedef struct ListeRepere { Element *debut; Element *fin; int taille; } Liste; /* initialisation de la liste */ void initialisation (Liste * liste);

/* INSERTION */ /* insertion dans une liste vide */ int ins_dans_liste_vide (Liste * liste, char *donnee); /* insertion au dbut de la liste */ int ins_debut_liste (Liste * liste, char *donnee); /* insertion a fin de la liste */ int ins_fin_liste (Liste * liste, Element * courant, char *donnee);

/* insertition ailleurs */ int ins_liste (Liste * liste, char *donnee, int pos);

/* SUPPRESSION */ int supp_debut (Liste * liste); int supp_dans_liste (Liste * liste, int pos);

int menu (Liste *liste,int *k); void affiche (Liste * liste); void detruire (Liste * liste); /* -------- FIN liste.h --------- */

liste_function.h
/***************************\

liste_function.h

\***************************/ void initialisation (Liste * liste) { liste->debut = NULL; liste->fin = NULL; liste->taille = 0; } /* insertion dans une liste vide */ int ins_dans_liste_vide (Liste * liste, char *donnee){ Element *nouveau_element; if ((nouveau_element = (Element *) malloc (sizeof (Element))) == NULL) return -1; if ((nouveau_element->donnee = (char *) malloc (50 * sizeof (char))) == NULL) return -1; strcpy (nouveau_element->donnee, donnee); nouveau_element->suivant = NULL; liste->debut = nouveau_element; liste->fin = nouveau_element;

liste->taille++; return 0; } /* insertion au dbut de la liste */ int ins_debut_liste (Liste * liste, char *donnee){ Element *nouveau_element; if ((nouveau_element = (Element *) malloc (sizeof (Element))) == NULL) return -1; if ((nouveau_element->donnee = (char *) malloc (50 * sizeof (char))) == NULL) return -1; strcpy (nouveau_element->donnee, donnee); nouveau_element->suivant = liste->debut; liste->debut = nouveau_element; liste->taille++; return 0; } /*insertion la fin de la liste */ int ins_fin_liste (Liste * liste, Element * courant, char *donnee){ Element *nouveau_element; if ((nouveau_element = (Element *) malloc (sizeof (Element))) == NULL) return -1; if ((nouveau_element->donnee = (char *) malloc (50 * sizeof (char))) == NULL) return -1; strcpy (nouveau_element->donnee, donnee); courant->suivant = nouveau_element; nouveau_element->suivant = NULL; liste->fin = nouveau_element; liste->taille++; return 0; } /* insertion la position demande */ int ins_liste (Liste * liste, char *donnee, int pos){ if (liste->taille < 2) return -1; if (pos < 1 || pos >= liste->taille) return -1;

Element *courant; Element *nouveau_element; int i; if ((nouveau_element = (Element *) malloc (sizeof (Element))) == NULL) return -1; if ((nouveau_element->donnee = (char *) malloc (50 * sizeof (char))) == NULL) return -1; courant = liste->debut; for (i = 1; i < pos; ++i) courant = courant->suivant; if (courant->suivant == NULL) return -1; strcpy (nouveau_element->donnee, donnee); nouveau_element->suivant = courant->suivant; courant->suivant = nouveau_element; liste->taille++; return 0; } /* suppression au dbut de la liste */ int supp_debut (Liste * liste){ if (liste->taille == 0) return -1; Element *supp_element; supp_element = liste->debut; liste->debut = liste->debut->suivant; if (liste->taille == 1) liste->fin = NULL; free (supp_element->donnee); free (supp_element); liste->taille--; return 0; } /* supprimer un element aprs la position demande */ int supp_dans_liste (Liste * liste, int pos){ if (liste->taille <= 1 || pos < 1 || pos >= liste->taille) return -1; int i; Element *courant; Element *supp_element;

courant = liste->debut; for (i = 1; i < pos; ++i) courant = courant->suivant; supp_element = courant->suivant; courant->suivant = courant->suivant->suivant; if(courant->suivant == NULL) liste->fin = courant; free (supp_element->donnee); free (supp_element); liste->taille--; return 0; } /* affichage de la liste */ void affiche (Liste * liste){ Element *courant; courant = liste->debut; while (courant != NULL){ printf ("%p - %s\n", courant, courant->donnee); courant = courant->suivant; } } /* detruire la liste */ void detruire (Liste * liste){ while (liste->taille > 0) supp_debut (liste); } int menu (Liste *liste,int *k){ int choix; printf("********** MENU **********\n"); if (liste->taille == 0){ printf ("1. Ajout du 1er element\n"); printf ("2. Quitter\n"); }else if(liste->taille == 1 || *k == 1){ printf ("1. Ajout au debut de la liste\n"); printf ("2. Ajout a la fin de la liste\n"); printf ("4. Suppression au debut de la liste\n"); printf ("6. Detruire la liste\n"); printf ("7. Quitter\n"); }else { printf ("1. Ajout au debut de la liste\n"); printf ("2. Ajout a la fin de la liste\n");

printf ("3. Ajout apres la position specifie\n"); printf ("4. Suppression au debut de la liste\n"); printf ("5. Suppression apres la position specifie\n"); printf ("6. Detruire la liste\n"); printf ("7. Quitter\n"); } printf ("\n\nFaites votre choix : "); scanf ("%d", &choix); getchar(); if(liste->taille == 0 && choix == 2) choix = 7; return choix; } /* -------- FIN liste_function.h --------- */

liste.c
/**********************\

liste.c

\**********************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "liste.h" #include "liste_function.h" int main (void) { char choix; char *nom; Liste *liste; Element *courant; if ((liste = (Liste *) malloc (sizeof (Liste))) == NULL) return -1; if ((nom = (char *) malloc (50)) == NULL) return -1; courant = NULL; choix = 'o'; initialisation (liste); int pos, k;

while (choix != 7){ choix = menu (liste, &k); switch (choix){ case 1: printf ("Entrez un element : "); scanf ("%s", nom); getchar (); if (liste->taille == 0) ins_dans_liste_vide (liste, nom); else ins_debut_liste (liste, nom); printf ("%d elements:deb=%s,fin=%s\n", liste->taille, liste->debut->donnee, liste->fin->donnee); affiche (liste); break; case 2: printf ("Entrez un element : "); scanf ("%s", nom); getchar (); ins_fin_liste (liste, liste->fin, nom); printf ("%d elements:deb=%s,fin=%s\n", liste->taille, liste->debut->donnee, liste->fin->donnee); affiche (liste); break; case 3: printf ("Entrez un element : "); scanf ("%s", nom); getchar (); do{ printf ("Entrez la position : "); scanf ("%d", &pos); } while (pos < 1 || pos > liste->taille); getchar (); if (liste->taille == 1 || pos == liste->taille){ k = 1; printf("-----------------------------------------------\n"); printf("/!\\Insertion echoue.Utilisez le menu {1|2} /!\\\n"); printf("-----------------------------------------------\n"); break; } ins_liste (liste, nom, pos); printf ("%d elements:deb=%s,fin=%s\n", liste->taille, liste->debut->donnee, liste->fin->donnee);

affiche (liste); break; case 4: supp_debut (liste); if (liste->taille != 0) printf ("%d elements:deb=%s,fin=%s\n", liste->taille, liste->debut->donnee, liste->fin->donnee); else printf ("liste vide\n"); affiche (liste); break; case 5: do{ printf ("Entrez la position : "); scanf ("%d", &pos); } while (pos < 1 || pos > liste->taille); getchar (); supp_dans_liste (liste, pos); if (liste->taille != 0) printf ("%d elements:deb=%s,fin=%s\n", liste->taille, liste->debut->donnee, liste->fin->donnee); else printf ("liste vide\n"); affiche (liste); break; case 6: detruire (liste); printf ("la liste a ete detruite : %d elements\n", liste>taille); break; } } return 0; }

Vous aimerez peut-être aussi