Partage
  • Partager sur Facebook
  • Partager sur Twitter

c# TP: créer une liste chainée générique

Sujet résolu
    4 octobre 2018 à 15:13:53

    Bonjour,

    Je suis actuellement en train de faire le cours de C# : Programmez en orienté objet avec C#.

    J'ai fait les précédent TPs et activité sans trop de problème mais je bloque sur le TP des chaines génériques. Quand je regarde la correction je comprend assez bien la logique du code, il n'est pas très compliqué mais il y a juste un élément qui me bloque et qui m'a bloqué quand j'ai essayé de faire le tp.

    Voila le code que j'ai:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ChaineGeneric
    {
        public class ListChaineGeneric<T>
        {
            //private int position;
            //private T List;
            public ListChaineGeneric<T>  Precedent { get; set; }
            public ListChaineGeneric<T> Suivant { get; set; }
            public T Valeur { get; set; }
    
            public ListChaineGeneric<T> Premier { get; private set; }
    
            public ListChaineGeneric<T> Dernier
            {
                get
                {
                    if (Premier == null)
                        return null;
                    ListChaineGeneric<T> dernier = Premier;
                    while (dernier.Suivant != null)
                    {
                        dernier = dernier.Suivant;
                    }
                    return dernier;
                }
            }
    
            public void Ajouter(T element)
            {
                if (Premier == null)
                {
                    Premier = new ListChaineGeneric<T> { Valeur = element };
                }
                else
                {
                    ListChaineGeneric<T> dernier = Dernier;
                    dernier.Suivant = new ListChaineGeneric<T> { Valeur = element, Precedent = dernier };
                }
    
            }
    
            public ListChaineGeneric<T> ObtenirElement(int indice)
            {
                ListChaineGeneric<T> temp = Premier;
                for (int i = 1; i <= indice; i++)
                {
                    if (temp == null)
                        return null;
                    temp = temp.Suivant;
                }
                return temp;
            }
    
            public void Inserer(T element, int indice)
            {
                if (indice == 0)
                {
                    ListChaineGeneric<T> temp = Premier;
                    Premier = new ListChaineGeneric<T> { Suivant = temp, Valeur = element };
                    temp.Precedent = Premier;
                }
                else
                {
                    ListChaineGeneric<T> elementAIndice = ObtenirElement(indice);
                    if (elementAIndice == null)
                        Ajouter(element);
                    else
                    {
                        ListChaineGeneric<T> precedent = elementAIndice.Precedent;
                        ListChaineGeneric<T> temp = precedent.Suivant;
                        precedent.Suivant = new ListChaineGeneric<T> { Valeur = element, Precedent = precedent, Suivant = temp };
                        temp.Precedent = precedent.Suivant;
                    }
                }
            }
        }
    }

    Mais ce qui me pose problème c'est juste les propriétés Suivante et Précédent :

    public ListChaineGeneric<T>  Precedent { get; set; }
    public ListChaineGeneric<T> Suivant { get; set; }

    Je ne vois pas comment l'algorithme comprend qu'il doit passer à la valeur suivante ou précédent juste en renseignant cette ligne par exemple:

    Console.WriteLine(listeChainee.Premier.Suivant.Valeur);

    Ça doit être tout bête mais j'avoue que j'ai un petit bug pour comprendre ça ^^'

    Merci d'avance de vos réponses.

    Bonne journée.




    • Partager sur Facebook
    • Partager sur Twitter
      4 octobre 2018 à 17:26:57

      Est-ce qu'on est d'accord pour dire que ce n'est qu'un exercice pompé d'un cours de C d'il y a 40 ans et qu'il n'a aucun intérêt pour l’apprentissage du C# et carrément dangereux depuis .NET 2.0 et ses generic, avec la classe List<T> (que la seconde ligne de votre code rend directement utilisable, LOL) ?

      Donc n'utilisez jamais ce machin, JAMAIS.

      Après, pour l'apprentissage d'un premier langage, et avec beaucoup de dessin dans la correction, pourquoi pas.

      Mais, à votre question, il doit pas voir beaucoup de dessin dans cette correction.

      On va déjà ce mettre d'accord que :

      public ListChaineGeneric<T>  Precedent { get; set; }
      public ListChaineGeneric<T> Suivant { get; set; }

      C'est l'équivalent à :

      private ListChaineGeneric<T> _precedent = null;
      public ListChaineGeneric<T>  Precedent {
          get{
              return _precedent;
          }
          set{
              _precedent = value;
          }
      }
      
      private ListChaineGeneric<T> _suivant  = null;
      public ListChaineGeneric<T> Suivant {
          get{
              return _suivant  ;
          }
          set{
              _suivant = value;
          }
      }

      Le code qui a besoin d'un champ "Premier" ET d'un champ précédent, c'est vraiment pas top.

      Je trouve que ça complique trop le machin.

      C'est une approche datant du C des années 70. Une approche moderne fait en sorte d'avoir 2 classes différentes et que les éléments de la chaine ne soit pas des maillons de la chaine mais juste des objets sans aucune connaissance de la chaine.

      Franchement, que tu bogues en regardant ce code, c'est bon signe, c'est que tu vois, peut-être inconsciemment, que le truc est un peu beaucoup foireux.

      Console.WriteLine(listeChainee.Premier.Suivant.Valeur);


      Seul "listeChainee.Premier.Suivant.Valeur" est intéressant.

      Je suppose que "listeChainee" est un ListChaineGeneric.

      Donc "listeChainee.Premier", c'est lire le contenu du champ "_premier" de cette liste "listeChainee".

      Bin, si on n'a rien appeler comme méthode sur ce "listeChainee", cela renverra "null", donc l'exécution du reste de la ligne fera péter une belle exception (est-ce que je vous ai dis que ce code et merdique ?).

      Le seul moyen d'avoir autre chose que "null" dans le champ "_premier" de "listeChainee", c'est d'avoir appelé la méthode "Ajouter" ce cet objet. Mais si t’appelles "listeChainee.Suivant.Suivant", ça passe à la compile, ça passe avec plein de chainons autre que "listeChainee", mais ça plantera avec "listeChainee" parce qu'on n'a appelé "Ajouter" en premier (sic!)  (C'est vraiment pas terrible cette classe "ListChaineGeneric", c'est même franchement caca).

      Enfin, bref, le code ne fonctionnera que si un certain nombre de trucs se sont fait dans un certain ordre précis, c'est foireux.

      Il devrait être possible de se passer de ce "Premier" qui est tout moisi.

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        4 octobre 2018 à 18:03:51

        Merci de votre réponse!

        Oui j'avais vu dans de vieux sujet sur ce TP que le code était pas vraiment au point mais ce qui me pose vraiment problème au delà de ça c'est de comprendre comment les propriétés "suivante" et "précédente" renvoient les bonnes valeurs au vu de ce code.

        par exemple si on a une liste 1,2,5,6,7. que l'on pointe actuellement sur la valeur 5, comment ça se fait que si l'on écrit quelque chose comme :

        ... .Suivant.Valeur

        on va avoir la valeur 6 qui va être renvoyée. Enfin j'aurais pensé que pour pouvoir faire ça il aurait fallu non pas une propriété mais une fonction comme :

        public int Precedent(int indice){
        ...
        }

        avec une boucle for et qui renvoi la valeur de l'indice - 1 par exemple. Alors que là il y a juste marqué :

        public ListChaineGeneric<T>  Precedent { get; set; }
        public ListChaineGeneric<T> Suivant { get; set; }

        et avec ca on peut marquer par exemple :

         while (dernier.Suivant != null)
             {
                 dernier = dernier.Suivant;
             }

        ici je ne comprend pas comment la variable dernier sait qu'il doit prendre la valeur suivante et pas la précédente par exemple.

        J'espère que ce que j'essaye de dire est clair, j'ai du louper quelque chose mais je ne vois quoi :/




        • Partager sur Facebook
        • Partager sur Twitter
          5 octobre 2018 à 11:48:47

          Salut,

          Regarde plus attentivement les méthodes "Ajouter" et "Insérer". Quand un nouveau maillon de la chaîne est créé, il est "connecté" aux maillons adjacents en modifiant les propriétés "Precedent" et "Suivant".

          • Partager sur Facebook
          • Partager sur Twitter
            5 octobre 2018 à 12:17:18

            ah oui merci! et j'ai galéré sur ça ... il y a des jours plus compliqués que d'autres ^^
            • Partager sur Facebook
            • Partager sur Twitter

            c# TP: créer une liste chainée générique

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown