1. // ==================================================================
  2. //      Auteur : Jean-Michel RICHER
  3. //      Email  : jean-michel.richer@univ-angers.fr
  4. // Institution : Université d'Angers, Faculté des Sciences
  5. // Département : Informatique
  6. // ==================================================================
  7. //
  8. // Objectif : Implantation itérative de liste simplement chaînée
  9. //
  10. // Spécificité : On passe en paramètre des sous-programmes qui
  11. // agissent sur les listes, un pointeur sur la liste à modifier
  12. //
  13. // Lors de l'appel de ces sous-programmes il faut donc passer
  14. // l'adresse de la liste
  15. //
  16. // L'implantation donnée ici utilise des macro-instructions afin
  17. // de rendre la lecture du code plus aisée. On utilise également
  18. // le type 'pointeur_sur_liste' plutôt que 'liste *' afin de
  19. // spécifier le passage en paramètre de la liste dans les sous-
  20. // programmes de manipulation
  21. // ==================================================================
  22.  
  23. #include <iostream>
  24. #include <sstream>
  25. using namespace std;
  26.  
  27. // ==================================================================
  28. // structures communes
  29. // ==================================================================
  30.  
  31. // définition du type de la valeur stockée par un élément de la liste
  32. using type_valeur = int;
  33.  
  34. // définition d'un élément (maillon) de la liste
  35. struct type_element_de_liste
  36. {
  37.     // pointeur sur l'élément suivant
  38.     type_element_de_liste *suivant;
  39.     // valeur stockée par cet élément
  40.     type_valeur valeur;
  41. };
  42.  
  43. // définition d'une liste comme un pointeur sur un élément
  44. using liste = type_element_de_liste *;
  45.  
  46. // définition de la liste vide
  47. const liste liste_vide = nullptr;
  48.  
  49. // ==================================================================
  50. // structures spécifiques à cette implantation
  51. // ==================================================================
  52.  
  53. // l'accès à la tête de la liste se fait par pointeur
  54. using pointeur_sur_liste = liste *;
  55.  
  56. // définition de macro-instructions qui permettent de rendre le
  57. // code plus lisible
  58.  
  59. // contenu du pointeur
  60. #define le_contenu_du_pointeur(l) (*l)
  61.  
  62. // élément suivant
  63. #define le_suivant_de(l) l->suivant
  64.  
  65. // valeur d'un élément
  66. #define la_valeur_de(l) l->valeur
  67.  
  68. // ==================================================================
  69. // Sous-programmes qui agissent sur une liste
  70. // ==================================================================
  71.  
  72. // Initialisation d'une liste
  73. void liste_initialiser(pointeur_sur_liste l)
  74. {
  75.     le_contenu_du_pointeur(l) = liste_vide;
  76. }
  77.  
  78. // Ajout en tete de la liste
  79. void liste_ajouter_en_tete(pointeur_sur_liste l, int valeur)
  80. {
  81.  
  82.     type_element_de_liste *nouvel_element = new type_element_de_liste;
  83.     le_suivant_de(nouvel_element) = le_contenu_du_pointeur(l);
  84.     la_valeur_de(nouvel_element) = valeur;
  85.  
  86.     le_contenu_du_pointeur(l) = nouvel_element;
  87. }
  88.  
  89. // Ajout en queue de la liste
  90. void liste_ajouter_en_queue(pointeur_sur_liste l, int valeur)
  91. {
  92.  
  93.     type_element_de_liste *nouvel_element = new type_element_de_liste;
  94.     le_suivant_de(nouvel_element) = liste_vide;
  95.     la_valeur_de(nouvel_element) = valeur;
  96.  
  97.     if (le_contenu_du_pointeur(l) == liste_vide)
  98.     {
  99.         le_contenu_du_pointeur(l) = nouvel_element;
  100.     }
  101.     else
  102.     {
  103.         // rechercher le dernier élément
  104.         liste dernier = le_contenu_du_pointeur(l);
  105.         while (le_suivant_de(dernier) != liste_vide)
  106.         {
  107.             dernier = le_suivant_de(dernier);
  108.         }
  109.  
  110.         le_suivant_de(dernier) = nouvel_element;
  111.     }
  112. }
  113.  
  114. // créer une liste à partir de données stokées
  115. // dans une chaîne de caractères
  116. void liste_creer(pointeur_sur_liste l, string data)
  117. {
  118.  
  119.     istringstream iss(data);
  120.     type_valeur valeur;
  121.  
  122.     while (iss >> valeur)
  123.     {
  124.         liste_ajouter_en_queue(l, valeur);
  125.     }
  126. }
  127.  
  128. // Vider une liste : supprimer tous ses éléments
  129. void liste_vider(pointeur_sur_liste l)
  130. {
  131.  
  132.     liste courant = le_contenu_du_pointeur(l);
  133.     liste suivant;
  134.  
  135.     while (courant != liste_vide)
  136.     {
  137.         suivant = le_suivant_de(courant);
  138.         delete courant;
  139.         courant = suivant;
  140.     }
  141.  
  142.     le_contenu_du_pointeur(l) = liste_vide;
  143. }
  144.  
  145. // Affichage de la liste
  146. void liste_afficher(pointeur_sur_liste l)
  147. {
  148.  
  149.     liste courant = le_contenu_du_pointeur(l);
  150.     while (courant != liste_vide)
  151.     {
  152.         cout << la_valeur_de(courant) << " ";
  153.         courant = le_suivant_de(courant);
  154.     }
  155.     cout << endl;
  156. }
  157.  
  158. // Tri de la liste sous forme de tri à bulle
  159. void liste_trier(pointeur_sur_liste l)
  160. {
  161.  
  162.     liste courant1 = le_contenu_du_pointeur(l);
  163.     while (courant1 != liste_vide)
  164.     {
  165.         liste courant2 = le_suivant_de(courant1);
  166.         while (courant2 != liste_vide)
  167.         {
  168.             if (la_valeur_de(courant1) > la_valeur_de(courant2))
  169.             {
  170.                 swap(la_valeur_de(courant1), la_valeur_de(courant2));
  171.             }
  172.             courant2 = le_suivant_de(courant2);
  173.         }
  174.         courant1 = le_suivant_de(courant1);
  175.     }
  176. }
  177.  
  178. void liste_supprimer_doublons(pointeur_sur_liste l)
  179. {
  180.  
  181.     liste courant = le_contenu_du_pointeur(l);
  182.  
  183.     // on parcourt la liste initiale à la recherche d'un doublon
  184.     // pour chaque élément
  185.     while (courant != liste_vide)
  186.     {
  187.         liste doublon = le_suivant_de(courant);
  188.  
  189.         // parcours des éléments restants dans la liste
  190.         liste precedent_doublon = courant;
  191.         while (doublon != liste_vide)
  192.         {
  193.  
  194.             // a t-on trouvé un doublon ?
  195.             if (la_valeur_de(courant) == la_valeur_de(doublon))
  196.             {
  197.                 // si oui, supprimer le doublon
  198.                 liste suivant_doublon = le_suivant_de(doublon);
  199.                 delete doublon;
  200.                 le_suivant_de(precedent_doublon) = suivant_doublon;
  201.  
  202.                 doublon = suivant_doublon;
  203.             }
  204.             else
  205.             {
  206.                 // sinon, passer à l'élément suivant
  207.                 precedent_doublon = doublon;
  208.                 doublon = le_suivant_de(doublon);
  209.             }
  210.         }
  211.  
  212.         courant = le_suivant_de(courant);
  213.     }
  214. }
  215.  
  216. // ==================================================================
  217. // Programme principal
  218. // ==================================================================
  219. // On insère des élément dans la liste (en tête, puis en queue) et
  220. // on affiche le résultat : 11 4 3 2 1 5 6 7 8 9 10 -1
  221. // on tri ensuite la liste : -1 1 2 3 4 5 6 7 8 9 10 11
  222. // ==================================================================
  223.  
  224. int main()
  225. {
  226.     liste l;
  227.  
  228.     liste_initialiser(&l);
  229.  
  230.     for (int i = 1; i < 5; ++i)
  231.     {
  232.         liste_ajouter_en_tete(&l, i);
  233.     }
  234.  
  235.     for (int i = 5; i < 11; ++i)
  236.     {
  237.         liste_ajouter_en_queue(&l, i);
  238.     }
  239.  
  240.     liste_ajouter_en_tete(&l, 11);
  241.     liste_ajouter_en_queue(&l, -1);
  242.  
  243.     cout << "liste initiale = ";
  244.     liste_afficher(&l);
  245.  
  246.     liste_trier(&l);
  247.  
  248.     cout << "liste triée = ";
  249.     liste_afficher(&l);
  250.  
  251.     liste_vider(&l);
  252.  
  253.     liste_creer(&l, "1 2 1 2 2 3 2 1");
  254.  
  255.     cout << "liste avec doublons = ";
  256.     liste_afficher(&l);
  257.  
  258.     liste_supprimer_doublons(&l);
  259.  
  260.     cout << "liste sans doublons = ";
  261.     liste_afficher(&l);
  262.  
  263.     liste_vider(&l);
  264.  
  265.     return EXIT_SUCCESS;
  266. }
  267.