Le langage C Structures de données Les listes simplement chaînées
Plan Principe Liste chaînée Vs. Tableau Construction Parcours Insertion Suppression Fonctions de manipulation
Principe Notion de maillon L'élément de base d'une liste chaînée s'appelle le maillon. Il est constitué : * d'un champ de données ; * d'un pointeur vers un maillon. données pointeur
Principe Maillon suivant Le champ pointeur vers un maillon pointe vers le maillon suivant de la liste. S'il n'y a pas de maillon suivant, le pointeur vaut NULL.
Principe Notion de liste Une liste simplement chaînée est un pointeur sur un maillon. Une liste vide est une liste qui ne contient pas de maillon. Elle a donc la valeur NULL. NULL
Principe La terminologie suivante est généralement employée : * le premier maillon de la liste est appelé tête ; * le dernier maillon de la liste est appelé queue. Rq : il se peut que les maillons qui composent la liste ne soit pas placées dans l'ordre en mémoire et encore moins de façon contiguë. NULL queue tête
Liste chaînée Vs. Tableau Dans une liste chaînée : la taille est inconnue au départ, la liste peut avoir autant d'éléments que votre mémoire le permet. Pour déclarer une liste chaînée il suffit de créer le pointeur qui va pointer sur le premier élément de votre liste chaînée, aucune taille n'est à spécifier donc. Il est possible d'ajouter, de supprimer, d'intervertir des éléments d'un liste chaînées en manipulant simplement leurs pointeurs.
Construction Le maillon Il faut déclarer les types constituant le maillon. Exemple : //pointeur sur maillon typedef struct s_maillon *p_maillon_t; //maillon typedef struct s_maillon { int valeur; p_maillon_t suivant; } maillon_t;
Construction La liste Maintenant on déclare les types constituant la liste : //liste typedef p_maillon_t liste_t; //pointeur sur liste typedef liste_t *p_liste_t;
Construction Deux types de fonctions vont interagir avec les listes : * les fonctions qui utilisent les listes : elles voient l'aspect externe des listes (les types liste_t et p_liste_t) * les fonctions qui gèrent les listes : elles voient l'aspect interne des listes (les types maillon_t et p_maillon_t). Les fonctions qui utilisent les listes n'ont pas à savoir que les listes sont constituées de maillons.
Parcours D’après son principe et sa construction, le parcours d’une liste simplement chaînée se fait uniquement du début vers la fin. Illustrons ceci par le calcul de la longueur d’une liste simplement chaînée. NULL
Parcours Longueur de la liste * Version itérative : int longueur_i(liste_t liste) { p_maillon_t p_maillon = liste; int longueur = 0; while (p_maillon != NULL) longueur++; p_maillon = p_maillon->suivant; } return longueur;
Parcours Longueur de la liste * Version récursive : int longueur_r(liste_t liste) { p_maillon_t p_maillon = liste; if (p_maillon != NULL) return 1 + longueur_r(p_maillon->suivant); } return 0;
Parcours Exercice : (correction en TP) Affichage de la liste. Écrire les fonctions permettant l’affichage du contenu de la liste en version itérative et récursive.
Insertion Insertion en tête
Insertion Insertion en tête { p_maillon_t p_maillon_ancien = *p_liste; void insertion_en_tete(p_liste_t p_liste, int entier) { p_maillon_t p_maillon_ancien = *p_liste; p_maillon_t p_maillon_nouveau = NULL; p_maillon_nouveau = malloc(sizeof(maillon_t)); p_maillon_nouveau->valeur = entier; p_maillon_nouveau->suivant = p_maillon_ancien; *p_liste = p_maillon_nouveau; }
Insertion Insertion en queue
Insertion Insertion en queue (version récursive) void insertion_en_queue(p_liste_t p_liste, int entier) { p_maillon_t p_maillon = *p_liste; if (p_maillon == NULL) insertion_en_tete(p_liste, entier); } else insertion_en_queue(&(p_maillon->suivant), entier); version itérative en exercice
Suppression Suppression en tête int suppression_en_tete(p_liste_t p_liste) { p_maillon_t p_maillon = *p_liste; int resultat = 0; if (p_maillon != NULL) resultat = p_maillon->valeur; *p_liste = p_maillon->suivant; free(p_maillon); } return resultat;
Suppression Suppression en queue (version récursive) int suppression_en_queue(p_liste_t p_liste) { p_maillon_t p_maillon = *p_liste; int resultat = 0; if (p_maillon != NULL) if (p_maillon->suivant == NULL) resultat = suppression_en_tete(p_liste); } else resultat = suppression_en_queue(&(p_maillon->suivant)); return resultat; version itérative en exercice
Fonctions de manipulation Au vu de l'utilisation des listes chaînées, il se dessine clairement quelques fonctions indispensables : * Initialisation (à vide) * Ajout d'un élément (à un emplacement i) * Suppression d'un élément (ième élément) * Accès à l'élément suivant * Accès aux données * Accès au premier élément de la liste * Accès au dernier élément de la liste * Suppression de la liste entière À préparer pour le TP