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