// ================================================================== // Auteur : Jean-Michel RICHER // Email : jean-michel.richer@univ-angers.fr // Institution : Université d'Angers, Faculté des Sciences // Département : Informatique // ================================================================== // // Objectif : Implantation itérative de liste simplement chaînée // // Spécificité : On passe en paramètre des sous-programmes qui // agissent sur les listes, une référence sur la liste à modifier // // Lors de l'appel de ces sous-programmes il faut donc passer // la liste (et non pas son adresse) // // L'implantation donnée ici utilise des macro-instructions afin // de rendre la lecture du code plus aisée. On utilise également // le type 'reference_sur_liste' plutôt que 'liste&' afin de // spécifier le passage en paramètre de la liste dans les sous- // programmes de manipulation // ================================================================== #include #include using namespace std; // ================================================================== // structures communes // ================================================================== // définition du type de la valeur stockée par un élément de la liste using type_valeur = int; // définition d'un élément (maillon) de la liste struct type_element_de_liste { // pointeur sur l'élément suivant type_element_de_liste *suivant; // valeur stockée par cet élément type_valeur valeur; }; // définition d'une liste comme un pointeur sur un élément using liste = type_element_de_liste *; // définition de la liste vide const liste liste_vide = nullptr; // ================================================================== // structures spécifiques à cette implantation // ================================================================== // l'accès à la tête de la liste se fait par pointeur using reference_sur_liste = liste &; // définition de macro-instructions qui permettent de rendre le // code plus lisible // contenu du pointeur #define le_contenu_de(l) l // élément suivant #define le_suivant_de(l) l->suivant // valeur d'un élément #define la_valeur_de(l) l->valeur // ================================================================== // Sous-programmes qui agissent sur une liste // ================================================================== // Initialisation d'une liste void liste_initialiser(reference_sur_liste l) { le_contenu_de(l) = liste_vide; } // Ajout en tete de la liste void liste_ajouter_en_tete(reference_sur_liste l, int valeur) { type_element_de_liste *nouvel_element = new type_element_de_liste; le_suivant_de(nouvel_element) = le_contenu_de(l); la_valeur_de(nouvel_element) = valeur; le_contenu_de(l) = nouvel_element; } // Ajout en queue de la liste void liste_ajouter_en_queue(reference_sur_liste l, int valeur) { type_element_de_liste *nouvel_element = new type_element_de_liste; le_suivant_de(nouvel_element) = liste_vide; la_valeur_de(nouvel_element) = valeur; if (le_contenu_de(l) == liste_vide) { le_contenu_de(l) = nouvel_element; } else { // rechercher le dernier élément liste dernier = le_contenu_de(l); while (le_suivant_de(dernier) != liste_vide) { dernier = le_suivant_de(dernier); } le_suivant_de(dernier) = nouvel_element; } } // créer une liste à partir de données stokées // dans une chaîne de caractères void liste_creer(reference_sur_liste l, string data) { istringstream iss(data); type_valeur valeur; while (iss >> valeur) { liste_ajouter_en_queue(l, valeur); } } // Vider une liste : supprimer tous ses éléments void liste_vider(reference_sur_liste l) { liste courant = le_contenu_de(l); liste suivant; while (courant != liste_vide) { suivant = le_suivant_de(courant); delete courant; courant = suivant; } le_contenu_de(l) = liste_vide; } // Affichage de la liste void liste_afficher(reference_sur_liste l) { liste courant = le_contenu_de(l); while (courant != liste_vide) { cout << la_valeur_de(courant) << " "; courant = le_suivant_de(courant); } cout << endl; } void liste_supprimer_doublons(reference_sur_liste l) { liste courant = le_contenu_de(l); // on parcourt la liste initiale à la recherche d'un doublon // pour chaque élément while (courant != liste_vide) { liste doublon = le_suivant_de(courant); // parcours des éléments restants dans la liste liste precedent_doublon = courant; while (doublon != liste_vide) { // a t-on trouvé un doublon ? if (la_valeur_de(courant) == la_valeur_de(doublon)) { // si oui, supprimer le doublon liste suivant_doublon = le_suivant_de(doublon); delete doublon; le_suivant_de(precedent_doublon) = suivant_doublon; doublon = suivant_doublon; } else { // sinon, passer à l'élément suivant precedent_doublon = doublon; doublon = le_suivant_de(doublon); } } courant = le_suivant_de(courant); } } // Tri de la liste sous forme de tri à bulle void liste_trier(reference_sur_liste l) { liste courant1 = le_contenu_de(l); while (courant1 != liste_vide) { liste courant2 = le_suivant_de(courant1); while (courant2 != liste_vide) { if (la_valeur_de(courant1) > la_valeur_de(courant2)) { swap(la_valeur_de(courant1), la_valeur_de(courant2)); } courant2 = le_suivant_de(courant2); } courant1 = le_suivant_de(courant1); } } // ================================================================== // Programme principal // ================================================================== // On insère des élément dans la liste (en tête, puis en queue) et // on affiche le résultat : 11 4 3 2 1 5 6 7 8 9 10 -1 // on tri ensuite la liste : -1 1 2 3 4 5 6 7 8 9 10 11 // ================================================================== int main() { liste l; liste_initialiser(l); for (int i = 1; i < 5; ++i) { liste_ajouter_en_tete(l, i); } for (int i = 5; i < 11; ++i) { liste_ajouter_en_queue(l, i); } liste_ajouter_en_tete(l, 11); liste_ajouter_en_queue(l, -1); cout << "liste initiale = "; liste_afficher(l); liste_trier(l); cout << "liste triée = "; liste_afficher(l); liste_vider(l); liste_creer(l, "1 2 1 2 2 3 2 1"); cout << "liste avec doublons = "; liste_afficher(l); liste_supprimer_doublons(l); cout << "liste sans doublons = "; liste_afficher(l); liste_vider(l); return EXIT_SUCCESS; }