Chapitre 3: Les listes simplement chaînées A.ABDALI MIPC/MIP S

Slides:



Advertisements
Présentations similaires
Chap. 1 Structures séquentielles : listes linéaires
Advertisements

Le langage C Structures de données
Commerce électronique Automne  Introduction  Création du panier d’achats  Migration du panier d’achats  Conclusion.
C++ Les fonctions. Présentation Utilité : Dès qu'un programme dépasse la centaine de lignes de code, il est pratique de pouvoir le décomposer en plusieurs.
L'image: Le codage des images BacPro SEN Lycée Condorcet.
SITC 10 rue de la libération Bâtiment C Neuilly-sur-Marne Processus création et envoi de newsletter changement du mot de passe.
CINI – Li115 1 Semaine 9 Algorithmes de tri ● Introduction ● Tri à bulle ● - principe ● - algorithme ● - efficacité ● Tri par sélection ● - principe, algorithme,
1/1/ Synthèse TD 3 Classe et adresse IP Bertrand Chesneau Morgan Nouet.
Chapitre 4 la représentation des nombres. Chapitre 4 : La représentation des nombres 1 - Introduction 1.1 – Notion de mot 2 - La représentation des entiers.
CINI – Li115 1 Semaine 3 Boucles (suite), tirages aléatoires, bibliothèque graphique ● Imbrication d'instructions if et for ● Boucles for imbriquées ●
CINI – Li115 1 Semaine 10 Les pointeurs ● Notion d'adresse ● Déclaration et utilisation de pointeurs ● "Types pointeur" et initialisation des pointeurs.
1 Programmation en C++ C++ de base ● Programme C++ ● Variables, objets, types ● Fonctions ● Namespace ● Tests ● Boucles ● Pointeurs, références.
1 Programmation en C++ C++ de base ● Programme C++ ● Variables, objets, types ● Types et opérations fondamentales ● Tests ● Boucles ● Pointeurs, références.
Tableaux en C Mardi 2/05.
Semaine 8 Retour sur les tableaux : fonctions et récursivité
Synthèse TP 2 Codeblock 1 Les objectifs de ce tp sont :
Les boites texte et dossier
Mettre à jour les données
Les Instructions Itératives (Les Boucles)
Introduction au Langage Pascal
Structure et Services « STS » Menu Structures : Divisions
DOC MYCK : Programmation
Deuxième partie : La courbe d’indifférence
Utiliser le dossier Mon EBSCOhost
Pas de variable globale
Les notions de classe et d'objet
Eléments d’Informatique Cours11 – Allocation dynamique, listes chaînées Catherine Recanati.
Allocation dynamique de mémoire
Pointeurs et langage C.
Javadoc et débogueur Semaine 03 Version A17.
Collecte de données CAPI
I21 Algorithmique et programmation II
7.1 Transformation linéaire
Principes de programmation (suite)
Algorithmique Langage C
11ième Classe (Mardi, 18 novembre) CSI2572
de toute série statistique
Semaine 11 Les pointeurs (suite)
Les fonctions.
Les fonctions.
Les bases de données et le modèle relationnel
Piles.
PROGRAMMATION INFORMATIQUE D’INGÉNIERIE II
L ES I NSTRUCTIONS I TÉRATIVES (L ES B OUCLES ) Réalisé par : OUZEGGANE Redouane Département de Technologie Faculté de Technologie – Université A.Mira,
Cours N°9: Algorithmiques Les Tableaux 1
Les tableaux.
La méthode du simplexe. 1) Algorithme du simplexe  Cet algorithme permet de déterminer la solution optimale, si elle existe, d’un problème de programmation.
Programmation en C++ C++ de base
Formules de calculs et Fonctions. Structure des formules de calcul Commencez toujours votre calcul par le signe =, ensuite sans laisser d’espaces, placez.
1 RECURSIVITE PRESENTATION Ch. PAUL ALGORITHMIQUE Présentation de la récursivité.
Type Concret – Type Abstrait
Bases de données sous Access. Initiation aux bases de données  Structure d’une base de données.
Les classes et les objets
Programmation Android Les listes
Les structures de base Listes chainées. Listes Les listes(similaire aux tableaux) sont des structures informatiques qui permettent de garder en mémoire.
Transition vers l’assignation automatique des stages à la résidence
Position, dispersion, forme
Information, Calcul, Communication
Structure de données utiles
Piles et files.
LISTES.
Présentation Chaînage dynamique Retour sur les tableaux
Listes Chaînées.
Chapter 11: Récursivité Java Software Solutions Second Edition
Tableau de bord d’un système de recommandation
Definition de html sommaire. Présentation de html, css et javascript Module 1.
Structure de données Les listes.
Boulain Joris, Handouz Yassine, Regnier Fabien, Giraud Antoine
App Inventor trucs Afficher une image depuis le Web ou Google Drive.
Les Commandes de base Linux. 1 L’aide sur les commandes Linux ◦ help : obtenir de l’aide pour une commande interne du shell. Elle permet aussi d'afficher.
Transcription de la présentation:

Chapitre 3: Les listes simplement chaînées A.ABDALI MIPC/MIP S4 2018

Problème des Tableaux : Toutefois, les tableaux se révèlent parfois assez limités. Par exemple, si vous créez un tableau de 10 cases et que vous vous rendez compte plus tard dans votre programme que vous avez besoin de plus d'espace, il sera impossible d'agrandir ce tableau. De même, il n'est pas possible d'insérer une case au milieu du tableau. Les listes chaînées Les listes chaînées représentent une façon d'organiser les données en mémoire de manière beaucoup plus flexible.

Représentation d'une liste chaînée Qu'est-ce qu'une liste chaînée ? Partant sur le modèle des tableaux. Un tableau peut être représenté en mémoire comme sur la fig. suivante. Il s'agit ici d'un tableau contenant des int par exemple Le problème des tableaux est qu'ils sont figés. Il n'est pas possible de les agrandir, à moins d'en créer de nouveaux, plus grands (fig. suivante).De même, il n'est pas possible d'y insérer une case au milieu, à moins de décaler tous les autres éléments.

Représentation d'une liste chaînée Une liste chaînée est un moyen d'organiser une série de données en mémoire. Cela consiste à assembler des structures en les liants entre elles à l'aide de pointeurs. On pourrait les représenter comme ceci :

Chaque élément peut contenir ce que l'on veut : un ou plusieurs int, double… En plus de cela, chaque élément possède un pointeur vers l'élément suivant Remarque : Contrairement aux tableaux, les éléments d'une liste chaînée ne sont pas placés côte à côte dans la mémoire. Chaque case pointe vers une autre case en mémoire qui n'est pas nécessairement stockée juste à côté.

Construction d'une liste chaînée Un élément de la liste Pour nos exemples, nous allons créer une liste chaînée de nombres entiers. Chaque élément de la liste aura la forme de la structure suivante : typedef struct Element Element; struct Element { int nombre; Element *suivant; };

Remarque: Nous avons créé ici un élément d'une liste chaînée Une donnée, ici un nombre de type int : on pourrait remplacer cela par n'importe quelle autre donnée (un double, un tableau…). Cela correspond à ce que vous voulez stocker, c'est à vous de l'adapter en fonction des besoins de votre programme Un pointeur vers un élément du même type appelé suivant. C'est ce qui permet de lier les éléments les uns aux autres : chaque élément « sait » où se trouve l'élément suivant en mémoire. Les cases ne sont pas côte à côte en mémoire. C'est la grosse différence par rapport aux tableaux. Cela offre davantage de souplesse car on peut plus facilement ajouter de nouvelles cases par la suite au besoin. En revanche, il ne sait pas quel est l'élément précédent, il est donc impossible de revenir en arrière à partir d'un élément avec ce type de liste. On parle de liste « simplement chaînée », alors que les listes « doublement chaînées » ont des pointeurs dans les deux sens et n'ont pas ce défaut. Elles sont néanmoins plus complexes.

La structure de contrôle En plus de la structure qu'on vient de créer (que l'on dupliquera autant de fois qu'il y a d'éléments), nous allons avoir besoin d'une autre structure pour contrôler l'ensemble de la liste chaînée. Elle aura la forme suivante : typedef struct Liste Liste; struct Liste { Element *premier; };

La structure de contrôle Cette structure Liste contient un pointeur vers le premier élément de la liste. En effet, il faut conserver l'adresse du premier élément pour savoir où commence la liste. Si on connaît le premier élément, on peut retrouver tous les autres en sautant d'élément en élément à l'aide des pointeurs suivant

Le dernier élément de la liste Il serait possible d'ajouter dans la structure Liste un pointeur vers le dernier Elément. il suffit de faire pointer le dernier élément de la liste vers NULL, c'est-à-dire de mettre son pointeur suivant à NULL. Cela nous permet de réaliser un schéma enfin complet de notre structure de liste chaînée

Le dernier élément de la liste

Les fonctions de gestion de la liste Nous avons créé deux structures qui permettent de gérer une liste chaînée: Element, qui correspond à un élément de la liste et que l'on peut dupliquer autant de fois que nécessaire. Liste, qui contrôle l'ensemble de la liste. Nous n'en aurons besoin qu'en un seul exemplaire.

Fonctions manipulant la liste chaînée Les fonctions qui vont manipuler la liste chaînée – initialiser la liste ; – ajouter un élément ; – supprimer un élément ; – afficher le contenu de la liste ; – supprimer la liste entière. Les fonctions qui vont manipuler la liste chaînée – initialiser la liste ; – ajouter un élément ; – supprimer un élément ; – afficher le contenu de la liste ; – supprimer la liste entière.

Initialiser la liste La fonction d'initialisation est la toute première que l'on doit appeler. Elle crée la structure de contrôle et le premier élément de la liste.

Liste *initialisation() { Liste *liste = malloc(sizeof(*liste)); Element *element = malloc(sizeof(*element)); if (liste == NULL || element == NULL) { exit(EXIT_FAILURE); } /*Constante EXIT_SUCCESS : l'exécution réussie d'un programme EXIT_FAILURE : l'exécution d'un programme échoue */ element->nombre = 0; element->suivant = NULL; liste->premier = element; return liste; }

Ajouter un élément Où va-t-on ajouter un nouvel élément ? Au début de la liste, à la fin, au milieu ? L’ajout d'un élément se fait en début de liste. Nous devons créer une fonction capable d'insérer un nouvel élément en début de liste. Pour nous mettre en situation, imaginons un cas semblable à la figure. Suivante : la liste est composée de trois éléments et on souhaite en ajouter un nouveau au début.

Ajouter un élément Il va falloir adapter le pointeur premier de la liste ainsi que le pointeur suivant de notre nouvel élément pour « insérer » correctement celui-ci dans la liste. Ci-joint le code source:

void insertion(Liste *liste, int nvNombre) { /* Création du nouvel élément */ Element *nouveau = malloc(sizeof(*nouveau)); if (liste == NULL || nouveau == NULL) { exit(EXIT_FAILURE); } nouveau->nombre = nvNombre; /* Insertion de l'élément au début de la liste */ nouveau->suivant = liste->premier; liste->premier = nouveau; }

La fonction insertion () prend en paramètre l'élément de contrôle liste (qui contient l'adresse du premier élément) et le nombre à stocker dans le nouvel élément que l'on va créer. Dans un premier temps, on alloue l'espace nécessaire au stockage du nouvel élément et on y place le nouveau nombre nvNombre. Il reste alors une étape délicate : l'insertion du nouvel élément dans la liste chaînée. Nous avons ici choisi pour simplifier d'insérer l'élément en début de liste. Pour mettre à jour correctement les pointeurs, nous devons procéder dans cet ordre précis : Faire pointer notre nouvel élément vers son futur successeur, qui est l'actuel premier élément de la liste ; Faire pointer le pointeur premier vers notre nouvel élément.

Supprimer un élément De même que pour l'insertion, nous allons ici nous concentrer sur la suppression du premier élément de la liste. Il est techniquement possible de supprimer un élément précis au milieu de la liste. La suppression ne pose pas de difficulté supplémentaire. Il faut cependant bien adapter les pointeurs de la liste dans le bon ordre pour ne « perdre » aucune information.

void suppression(Liste *liste) { if (liste == NULL) { exit(EXIT_FAILURE); } if (liste->premier != NULL) { Element *aSupprimer = liste->premier; liste->premier = liste->premier->suivant; free(aSupprimer); }

Supprimer un élément Ces vérifications effectuées, on peut sauvegarder l'adresse de l'élément à supprimer dans un pointeur aSupprimer. On adapte ensuite le pointeur premier vers le nouveau premier élément, qui est actuellement en seconde position de la liste chaînée. Il ne reste plus qu'à supprimer l'élément correspondant à notre pointeur aSupprimer avec un free.

Cette fonction est courte mais sauriez-vous la réécrire ? Il faut bien comprendre qu'on doit faire les choses dans un ordre précis : 1.Faire pointer premier vers le second élément ; 2.Supprimer le premier élément avec un free. Si on faisait l'inverse, on perdrait l'adresse du second élément !

Pour bien visualiser ce que contient notre liste chaînée, une fonction d'affichage serait idéale ! Il suffit de partir du premier élément et d'afficher chaque élément un à un en « sautant » de bloc en bloc. void afficherListe(Liste *liste) { if (liste == NULL) { exit(EXIT_FAILURE); } Element *actuel = liste->premier; while (actuel != NULL) { printf("%d -> ", actuel->nombre); actuel = actuel->suivant; } printf("NULL\n"); }

Cette fonction est simple : on part du premier élément et on affiche le contenu de chaque élément de la liste (un nombre). On se sert du pointeur suivant pour passer à l'élément qui suit à chaque fois. On peut s'amuser à tester la création de notre liste chaînée et son affichage avec un main :

main int main() { Liste *maListe = initialisation(); insertion(maListe, 4); insertion(maListe, 8); insertion(maListe, 15); suppression(maListe); afficherListe(maListe); getch(); return 0; }

Autres Méthodes pour manipuler les listes chaînées Structures de données

Ajout et suppression d’éléments

Déclaration en C d'une liste chaînée #include typedef struct element element; struct element { int val; element *nxt; }; typedef element* llist;

Une liste simplement chaînée est un pointeur sur un maillon. Une liste vide ne contient pas maillon. Elle a donc la valeur NULL. Le premier maillon de la liste est appelé tête Le dernier maillon de la liste est appelé queue.

Voila comment déclarer une liste chainée (vide pour l'instant) : #include typedef struct element element; struct element { int val; struct element *nxt; }; typedef element* llist; int main() { /* Déclarons 3 listes chaînées de façons différentes mais équivalentes */ llist ma_liste1 = NULL; element *ma_liste2 = NULL; struct element *ma_liste3 = NULL; return 0; }

Remarque Il est important de toujours initialiser la liste chaînée à NULL. Le cas échéant, elle sera considérée comme contenant au moins un élément. C'est une erreur fréquente. A garder en mémoire donc. De manière générale, il est plus sage de toujours initialiser vos pointeurs.

Manipulation des listes chaînées Ajouter un élément : Lorsque nous voulons ajouter un élément dans une liste chaînée, il faut savoir où l'insérer. Les deux ajouts génériques des listes chaînées sont les ajouts en tête, et les ajout en fin de liste. Nous allons étudier ces deux moyens d'ajouter un élément à une liste.

Ajouter en tête : Lors d'un ajout en tête, nous allons créer un élément, lui assigner la valeur que l'on veut ajouter, puis pour terminer, raccorder cet élément à la liste passée en paramètre. Lors d'un ajout en tête on devra donc assigner à nxt l'adresse du premier élément de la liste passé en paramètre. Visualisons tout ceci sur un schéma :

Ajout en tête Code : C llist ajouterEnTete(llist liste, int valeur) { /* On cr é e un nouvel é l é ment */ element* nouvelElement = malloc(sizeof(element)); /* On assigne la valeur au nouvel é l é ment */ nouvelElement->val = valeur; /* On assigne l'adresse de l' é l é ment suivant au nouvel é l é ment */ nouvelElement->nxt = liste; /* On retourne la nouvelle liste, ie. le pointeur sur le premier é l é ment */ return nouvelElement; } C'est l'ajout le plus simple des deux. Il suffi de créer un nouvel élément puis de le relier au début de la liste originale. Si l'original est NULL (vide) c'est NULL qui sera assigné au champ nxt du nouvel element. La liste contiendra dans ce cas là un seul élément

Ajouter en fin de liste : Cette fois ci c'est un peu plus compliqué. Il nous faut tout d'abord créer un nouvel élément, lui assigner sa valeur, et mettre l'adresse de l'élément suivant à NULL. En effet comme cet élément va terminer la liste nous devons signaler qu'il n'y a plus d'élément suivant. Ensuite il faut faire pointer le dernier élément de la lliste originale sur le nouvel élément que nous venons de créer. Pour ce faire il faut créer un pointeur temporaire sur element qui va se déplacer d'éléments en éléments et regarder si cet élément est le dernier de la liste. Un élément sera forcément le dernier de la liste si NULL est assigné à son champ nxt.

Code : C llist ajouterEnFin(llist liste, int valeur) { /* On cr é e un nouvel é l é ment */ element* nouvelElement = malloc(sizeof(element)); /* On assigne la valeur au nouvel é l é ment */ nouvelElement->val = valeur; /* On ajoute en fin donc aucun é l é ment ne va suivre */ nouvelElement->nxt = NULL; if(liste == NULL) { /* Si la liste est vide il suffit de renvoyer l' é l é ment cr é e */ return nouvelElement; } else { /* Sinon on parcours la liste à l'aide d'un pointeur temporaire et on indique que le dernier é l é ment de la liste est reli é au nouvel é l é ment */ element* temp=liste; while(temp->nxt != NULL) { temp = temp->nxt; } temp->nxt = nouvelElement; return liste; } }

Affichage de la liste 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) { element *tmp = liste; /* Tant que l'on est pas au bout de la liste */ while(tmp != NULL) { /* On affiche */ printf("%d ", tmp->val); /* On avance d'une case */ tmp = tmp->nxt; } }printf

Exemple Complet : #include typedef struct element element; struct element { int val; struct element *nxt; }; typedef element* llist; llist ajouterEnTete(llist liste, int valeur) { /* On crée un nouvel élément */ element* nouvelElement = malloc(sizeof(element)); /* On assigne la valeur au nouvel élément */ nouvelElement->val = valeur; /* On assigne l'adresse de l'élément suivant au nouvel élément */ nouvelElement->nxt = liste; printf("%d ", nouvelElement->val); /* On retourne la nouvelle liste, ie. le pointeur sur le premier élément */ return nouvelElement; } llist ajouterEnFin(llist liste, int valeur) { /* On crée un nouvel élément */ element* nouvelElement = malloc(sizeof(element)); /* On assigne la valeur au nouvel élément */ nouvelElement->val = valeur; /* On ajoute en fin donc aucun élément ne va suivre */ nouvelElement->nxt = NULL; if(liste == NULL) { /* Si la liste est vide il suffit de renvoyer l'élément crée */ return nouvelElement; } else { /* Sinon on parcours la liste à l'aide d'un pointeur temporaire et on indique que le dernier élément de la liste est relié au nouvel élément */ element* temp=liste; while(temp->nxt != NULL) { temp = temp->nxt; } temp->nxt = nouvelElement; return liste; } void afficherListe(llist liste) { element *tmp = liste; /* Tant que l'on est pas au bout de la liste */ while(tmp != NULL) { /* On affiche */ printf("%d ", tmp->val); /* On avance d'une case */ tmp = tmp->nxt; } int main() { 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); system("pause"); return 0; }

Supprimer un élément en tête Il s'agit là de supprimer le premier élément de la liste. Pour ce faire, il nous faudra utiliser la fonction free que vous connaissez certainement. Si la liste n'est pas vide, on stocke l'adresse du premier élément de la liste après suppression (i.e. l'adresse du 2ème élément de la liste originale). On supprime le premier élément, et on renvoie la nouvelle liste. Attention quand même à ne pas libérer le premier élément avant d'avoir stocké l'adresse du second, sans quoi il sera impossible de la récupérer.

Code : llist supprimerElementEnTete(llist liste){ if(liste != NULL) { /* Si la liste est non vide, on se prépare à renvoyer l'adresse de l'élément en 2ème position */ element* aRenvoyer = liste->nxt; liste->nxt=liste->nxt->nxt ; /* On libère le premier élément */ free(aRenvoyer); /* On retourne le nouveau début de la liste */ return liste; } else { return NULL; }}

Supprimer un élément en fin de liste Cette fois-ci, il va falloir parcourir la liste jusqu'à son dernier élément, indiquer que l'avant-dernier élément va devenir le dernier de la liste et libérer le dernier élément pour enfin retourner le pointeur sur le premier élément de la liste d'origine.

llist supprimerElementEnFin(llist liste) { /* Si la liste est vide, on retourne NULL */ if(liste == NULL) return NULL; /* Si la liste contient un seul élément */ if(liste->nxt == NULL) { /* On le libère et on retourne NULL (la liste est maintenant vide) */ free(liste); return NULL; } /* Si la liste contient au moins deux éléments */ element* tmp = liste; element* ptmp = liste; /* Tant qu'on n'est pas au dernier élément */ while(tmp->nxt != NULL) { /* ptmp stock l'adresse de tmp */ ptmp = tmp; /* On déplace tmp (mais ptmp garde l'ancienne valeur de tmp */ tmp = tmp->nxt; } /* A la sortie de la boucle, tmp pointe sur le dernier élément, et ptmp sur l'avant-dernier. On indique que l'avant-dernier devient la fin de la liste et on supprime le dernier élément */ ptmp->nxt = NULL; free(tmp); return liste; }

Insertion d’un élément au milieu de la liste typedef struct elem { int valeur; struct elem* suiv; }elem ; typedef elem* elemt; //initialisation de la liste elemt Mysl = NULL;

Étapes: L'insertion s'effectuera après une certaine position passée en argument à la fonction. Étapes: 1.allocation de la mémoire pour le nouvel élément 2.remplir le champ de données du nouvel élément 3.choisir une position dans la liste (l'insertion se fera après la position choisie) 4.le pointeur suivant du nouvel élément pointe vers l'adresse sur laquelle pointe le pointeur suivant d'élément courant. (cette explication est un peu tordue, mais l'image vous éclaira ;-) 5.le pointeur suivant de l'élément courant pointe vers le nouvel élément 6.les pointeurs debut et fin ne change pas 7.la taille est incrémentée d'une unité

insert Voyons de suite la fonction Insert qui doit faire une insertion ordonnée des éléments. On lui passera donc comme paramètre la valeur à sauvegarder et l'adresse du pointeur identifiant la liste.

Code insert void Insert(elemt *sl, int Val){ elemt tmp = NULL; elemt csl = *sl; elemt elem = malloc(sizeof(elem)); if(!elem) exit(EXIT_FAILURE); elem->valeur = Val; while(csl && csl->valeur < Val) { tmp = csl; csl = csl->suiv; } elem->suiv = csl; if(tmp) tmp->suiv = elem; else *sl = elem; }

Longueur d’une liste int Length(elemt sl) { int n=0; while(sl) { n++; sl = sl->suiv; } return n; }

Retrait de quelques éléments de la liste int Pop(elemt *sl) { int Val; elemt tmp; if(!*sl) return -1; tmp = (*sl)->suiv; Val = (*sl)->valeur; free(*sl); *sl = tmp; return Val; }

Vidage de la liste void Clear(elemt *sl) { elemt tmp; while(*sl) { tmp = (*sl)->suiv; free(*sl); *sl = tmp; }

Affichage de la liste void View(elemt sl) { while(sl) { printf("%d\n",sl->valeur); sl = sl->suiv; }

Programme complet #include typedef struct elem { int valeur; struct elem* suiv; }elem ; typedef elem* elemt; //initialisation de la liste elemt Mysl = NULL; void Insert(elemt *sl, int Val){ elemt tmp = NULL; elemt csl = *sl; elemt elem = malloc(sizeof(elem)); if(!elem) exit(EXIT_FAILURE); elem->valeur = Val; while(csl!=NULL && csl->valeur < Val) { tmp = csl; csl = csl->suiv; } elem->suiv = csl; if(tmp) tmp->suiv = elem; else *sl = elem; } int Length(elemt sl) { int n=0; while(sl) { n++; sl = sl->suiv; } return n;} int Pop(elemt *sl) { int Val; elemt tmp; if(!*sl) return -1; tmp = (*sl)->suiv; Val = (*sl)->valeur; free(*sl); *sl = tmp; return Val; } void Clear(elemt *sl) { elemt tmp; while(*sl) { tmp = (*sl)->suiv; free(*sl); *sl = tmp; } void View(elemt sl) { while(sl) { printf("%d\n",sl->valeur); sl = sl->suiv; } int main(){ elem *S1 = NULL; Insert(&S1,12); Insert(&S1,8); Insert(&S1,3); Insert(&S1,5); Insert(&S1,9); Insert(&S1,5); Insert(&S1,2); Insert(&S1,7); printf("Nb d'elements : %d\n",Length(S1)); View(S1); /* Déclarons 3 listes chaînées de façons différentes mais équivalentes */ puts("Retrait de deux elements :"); printf("%d\n",Pop(&S1)); printf("Nb d'elements : %d\n",Length(S1)); View(S1); puts("Vidage de la liste puis ajout de 3 elements :"); Clear(&S1); Insert(&S1,3); Insert(&S1,9); Insert(&S1,5); printf("Nb d'elements : %d\n",Length(S1)); View(S1); Clear(&S1); getch(); return 0; }

Suppression après une position void supp_dans_liste(elem* S, int pos){ int i; elem *supp_element; for (i = 0; i <pos; ++i) S = S->suiv; supp_element = S->suiv; S->suiv = S->suiv->suiv; // if(S->suiv == NULL) // S->suiv = S; free (supp_element); }

Rechercher un élément dans une liste Le but du jeu cette fois est de renvoyer l'adresse du premier élément trouvé ayant une certaine valeur. Si aucun élément n'est trouvé on renverra NULL. L'intérêt est de pouvoir, une fois le premier élément trouvé, chercher la prochaine occurrence en recherchant à partir de elementTrouve->nxt. On parcours donc la liste jusqu'au bout et dès qu'on trouve un élément qui correspond à ce que l'on recherche, on renvoie son adresse

code llist rechercherElement(llist liste, int valeur) { element *tmp=liste; /* Tant que l'on est pas au bout de la liste */ while(tmp != NULL) { if(tmp->val == valeur) { /* Si l'élément à la valeur recherché on renvois son adresse */ return tmp; } tmp = tmp->nxt; } return NULL; }

Compter le nombre d'occurrences d'une valeur : Pour ce faire nous allons utiliser la fonction précédente permettant de rechercher un élément. On cherche une première occurrence, si on la trouve alors on continue la recherche à partir de l'élément suivant, et ce tant qu'il reste des occurrences de la valeur recherchée. Il est aussi possible d'écrire cette fonction sans utiliser la précédente bien entendu, en parcourant l'ensemble de la liste avec un compteur que l'on incrémente à chaque fois que l'on passe sur un élément ayant la valeur recherché. Cette fonction n'est pas beaucoup plus compliqué mais il est intéressant d'un point de vue algorithmique de réutiliser des fonctions pour simplifier nos codes.

code int nombreOccurences(llist liste, int valeur) { int i = 0; /* Si la liste est vide, on renvois 0 */ if(liste == NULL) return 0; /* Sinon tant qu'il y a encore un élément ayant la val = valeur */ while((liste = rechercherElement(liste, valeur)) != NULL) { /* On incrémente */ liste = liste->nxt; i++; } /* Et on retourne le nombre d'occurence */ return i; }

Récupérer la valeur d'un élément : Il suffit simplement de renvoyer à l'utilisateur la valeur d'un élément. Il faudra renvoyer un code d'erreur entier si l'élément n'existe pas (la liste est vide), c'est donc à vous de définir une macro selon l'utilisation que vous voulez faire des listes chainées. Dans ce code je considère qu'on ne travaille qu'avec des nombres entiers positifs, on renverra donc -1 pour une erreur. Vous pouvez mettre ici n'importe quelle valeur que vous êtes sur de ne pas utiliser dans votre liste. Une autre solution consiste à renvoyer un pointeur sur int au lieu d'un int, vous laissant donc la possibilité de renvoyer NULL

code #define ERREUR -1 int valeur(llist liste) { return ((liste == NULL)?ERREUR:(liste->val)); }

Compter le nombre d'éléments d'une liste chainée : int nombreElements(llist liste) { /* Si la liste est vide, il y a 0 éléments */ if(liste == NULL) return 0; /* Sinon il y a un élément (celui que l'on est en train de traiter) plus le nombre d'éléments contenus dans le reste de la liste */ return nombreElements(liste->nxt)+1; }

Effacer tous les éléments ayant une certaine valeur : llist supprimerElement(llist liste, int valeur) { /* Liste vide, il n'y a plus rien à supprimer */ if(liste == NULL) return NULL; /* Si l'élément en cours de traitement doit être supprimé */ if(liste->val == valeur) { /* On le supprimer en prenant soin de mémoriser l'adresse de l'élément suivant */ element* tmp = liste->nxt; free(liste); /* L'élément ayant été supprimé, la liste commencera à l'élément suivant pointant sur une liste qui ne contient plus aucun élément ayant la valeur recherchée */ tmp = supprimerElement(tmp, valeur); return tmp; } else { /* Si l'élement en cours de traitement ne doit pas être supprimé alors la liste finale commencera par cet élément et suivra une liste ne contenant plus d'élément ayant la valeur recherchée */ liste->nxt = supprimerElement(liste->nxt, valeur); return liste; } }