// ================================================================== // 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, un pointeur sur la liste à modifier // // Lors de l'appel de ces sous-programmes il faut donc passer // l'adresse de la liste // // L'implantation donnée ici utilise des macro-instructions afin // de rendre la lecture du code plus aisée. On utilise également // le type 'pointeur_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 pointeur_sur_liste = liste *; // définition de macro-instructions qui permettent de rendre le // code plus lisible // contenu du pointeur #define le_contenu_du_pointeur(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(pointeur_sur_liste l) { le_contenu_du_pointeur(l) = liste_vide; } // Ajout en tete de la liste void liste_ajouter_en_tete(pointeur_sur_liste l, int valeur) { type_element_de_liste *nouvel_element = new type_element_de_liste; le_suivant_de(nouvel_element) = le_contenu_du_pointeur(l); la_valeur_de(nouvel_element) = valeur; le_contenu_du_pointeur(l) = nouvel_element; } // Ajout en queue de la liste void liste_ajouter_en_queue(pointeur_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_du_pointeur(l) == liste_vide) { le_contenu_du_pointeur(l) = nouvel_element; } else { // rechercher le dernier élément liste dernier = le_contenu_du_pointeur(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(pointeur_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(pointeur_sur_liste l) { liste courant = le_contenu_du_pointeur(l); liste suivant; while (courant != liste_vide) { suivant = le_suivant_de(courant); delete courant; courant = suivant; } le_contenu_du_pointeur(l) = liste_vide; } // Affichage de la liste void liste_afficher(pointeur_sur_liste l) { liste courant = le_contenu_du_pointeur(l); while (courant != liste_vide) { cout << la_valeur_de(courant) << " "; courant = le_suivant_de(courant); } cout << endl; } // Tri de la liste sous forme de tri à bulle void liste_trier(pointeur_sur_liste l) { liste courant1 = le_contenu_du_pointeur(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); } } void liste_supprimer_doublons(pointeur_sur_liste l) { liste courant = le_contenu_du_pointeur(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); } } // ================================================================== // 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; }