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