Partage
  • Partager sur Facebook
  • Partager sur Twitter

C++ liste chaînée

c++ cours de Mathieu Nébra

Sujet résolu
14 août 2018 à 11:10:49

Bonjour à tous,

Mathieu, dans son cours de C++ dit à propos des listes chaînées de type list(https://openclassrooms.com/fr/courses/1894236-programmez-avec-le-langage-c/1903301-iterateurs-et-foncteurs) :

L'avantage de cette structure de données est que l'on peut facilement ajouter des éléments au milieu. Il n'est pas nécessaire de décaler toute la suite comme dans l'exemple de la bibliothèque du chapitre précédent. Mais (il y a toujours un mais) on ne peut pas directement accéder à une case donnée… tout simplement parce qu'on ne sait pas où elle se trouve dans la mémoire.
. On est obligé de suivre toute la chaîne des éléments. Pour aller à la huitième case, il faut aller à la première case, suivre le pointeur jusqu'à la deuxième, suivre le pointeur jusqu'à la troisième et ainsi de suite jusqu'à la huitième. C'est donc très coûteux.

Je ne saisis pas la différence de difficulté algorithmique entre le fait d'ajouter des éléments au milieu et le fait d'accéder à une case donnée.

Est-ce parce que l'élément du milieu est situé à la position n/2 (donc on connaît la position) ?

Merci pour vos explicitations

-
Edité par pseudo-simple 14 août 2018 à 11:16:55

  • Partager sur Facebook
  • Partager sur Twitter
14 août 2018 à 12:08:17

Ce n'est pas une question de C++, mais d'algorithmique.

Cf https://fr.wikipedia.org/wiki/Liste_cha%C3%AEn%C3%A9e 

Dans un vector, les elements sont contingues en memoire, tu peux aller directement a n'importe quel element en memoire (c'est a dire trouver son adresse memoire) en calculant a partir de l'adresse memoire du premier element du tableau.

Avec une liste chainee, les elements sont n'importe où en memoire et il n'est pas possible de calculer l'adresse. Il faut partir du premier element et aller a l'element suivant jusqu'a trouver l'element recherché.

Pour inserer un element dans un vector, cela veut dire qu'il faut copier tous les elements qui se trouvent apres l'element inseré. Dans la cas d'une liste, il faut juste changer les pointeurs, il n'est pas necessaire de copier.

En pratique, ce n'est pas vrai. L'insertion (meme avec les copies) dans un vector est souvent plus rapide qu'une insertion dans une liste. Utilises des std::vector par defaut.

-
Edité par gbdivers 14 août 2018 à 12:10:29

  • Partager sur Facebook
  • Partager sur Twitter
14 août 2018 à 12:29:17

Salut,

Tu devrais aussi suivre un autre cours, un qui t'apprendrait à ne pas utiliser des listes pour récupérer des éléments à la manière d'un simple tableau de données par exemple.

Dans un std::vector, les éléments sont placé les uns à la suite des autres, raison pour laquelle nous pouvons accéder à un élément de cette manière :

vec[n];

Un std::liste, lui, n'est pas ordonné à la façon d'un std::vector. On ne l'utilisera d'ailleurs pas pour récupérer des éléments à des indexe précis, comme on le ferait pour un tableau. Il y a une façon d'accéder à un élément "précis", mais c'est coûteux (puisque "aléatoire") :

std::list<T> MyList;
...
std::list<T>::iterator it = MyList.begin();
std::advance(it, n);

L'itérateur it pointe désormais l'élément situé à la position n :

T item = *it;

Mais tu as des chances de tomber sur un autre élément que celui attendu. En effet, la liste enregistre ses données dynamiquement (pas de mémoire pré allouée) sur le tas.

-
Edité par vanaur 14 août 2018 à 12:30:09

  • Partager sur Facebook
  • Partager sur Twitter

Le meilleur moyen de prédire l'avenir, c'est de l'inventer | N'oubliez pas [résolu] et +1 | Excusez mon ôrtograffe, j'essaie de l'améliorer...

14 août 2018 à 13:22:20

C'est que le cours est rédigé de façon épouvantable, avec un manque de précision que ne remarquent pas les débutants, mais dont ils sont vite les victimes.

Si on prend par exemple (pour les listes chainées) "on ne peut pas directement accéder à une case donnée… parce qu'on ne sait pas où elle se trouve dans la mémoire."


Qu'est ce que ça veut dire "une case donnée" ?   Si la case est "donnée" par un pointeur sur la cellule qui contient la valeur, on sait parfaitement où elle est.  Si on dit "la première", on sait aussi.

Ce qu'il fallait dire, c'est qu'on n'a pas accès directement à autre chose qu'au premier élément de la liste.   Ensuite, si on cherche une case par son contenu, ou par son indice (0 pour la première, 1 pour la seconde, etc), il faudra parcourir la chaine, d'élément en élément.  Et ça prendra un temps proportionnel à la "distance" où se trouve ce qu'on  cherche.

Dans un tableau, par contre, l'accès par indice est direct. Mais pas par contenu.

  • Partager sur Facebook
  • Partager sur Twitter
14 août 2018 à 13:37:02

Merci beaucoup à vous 3 (Gbdivers, vanaur, MichelBillaud). Vous êtes très clairs.

Vous avez parfaitement répondu à ma question.

J'ai mis un +1 à chacun et je passe le sujet en résolu.

-
Edité par pseudo-simple 14 août 2018 à 13:37:36

  • Partager sur Facebook
  • Partager sur Twitter
29 octobre 2018 à 23:18:25

Bonjour j'ai un petit souci avec mon code source en C je veux créer une méthode pour insérer des étudiants et calculer par la suite leur moyenne mais je arrive a afficher les étudiant saisis mais je n arrive pas a afficher les moyennes par la suites .Aidez moi svp plait .

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// Déclarations des types pour la structure note
typedef struct Note
{ int coef;
  int note;
  int  moy;
  struct Note* suivant ;

} Note;
// Déclarations des types pour la structure etudiant
typedef struct Etudiant
{
  struct Etudiant*prec ;
  char numero[10];
  char nom[30];
  char prenom[10];
  int  moy;
  struct Note*eval ;
  struct Etudiant*suivant ;

} Etudiant;
// Déclarations des pointeurs etudiant et pointeur note
typedef Etudiant*Pe;
typedef Note*Pn;
// Variables
Pe p1;
Pe p ;
Pn p2;
Pe petu;
Pn pnote;
Pe tete;

void Inserer_Etudiant(Pe tete)
{
int rep=0;
int dec=1;
int rep1=0;
int dec1=1;

    ///Creation du premier element de liste Etudiant-----------
    (petu) = malloc(sizeof(Etudiant));

    printf("Saisissez le numero de l'etudiant : ");
    gets(petu->numero);

    printf("Saisissez le nom de l'etudiant : ");
    gets(petu->nom);

    printf("Saisissez le prenom de l'etudiant : ");
    gets(petu->prenom);

    // Insertion de notes
    printf("Vouliez vous ajouter une nouvelle note - Repondez par (0/1)");
    scanf("%i",&rep1);
    dec1 = rep1;

    /// Saisit de la premiere note ou rien ------------------------------------------
    if (dec1==0)
    {
        petu->eval= NULL;
    }
    else  // On saisit la premiere note ...
    {
        (pnote) =  malloc(sizeof(Note));
        printf("Saisissez la note de l'etudiant : ");
        scanf("%d",&pnote->note);

        printf("Saisissez le coefficient de cette note : ");
        scanf("%d",&pnote->coef);

        petu->eval =pnote ;
        p2 = pnote ;

    }

    ///Saisir de la deuxienne note ----
    if(dec1 != 0)
    {

        dec1 ==0;
                //Saisir deuxiemem note
        printf("Vouliez vous ajouter une nouvelle note - Repondez par (0/1)");
        scanf("%i",&rep1);
        dec1 = rep1;
        if(dec==1)
        {
        (pnote) =  malloc(sizeof(Note));
        p2->suivant = pnote ;
        printf("Saisissez la note de l'etudiant : ");
        scanf("%d",&pnote->note);

        printf("Saisissez le coefficient de cette note : ");
        scanf("%d",&pnote->coef);

        p2 = pnote ;
        }

    }

    /// FIn de saisie de note ------
    pnote->suivant = NULL;

    /// FIn de la saisie etudiant
    tete = petu ;
    p1 = petu;

    ///-------------------------------------------------------------------------------------

    ///Creation du deuxieme element de liste Etudiant-----------
    printf("Vouliez vous ajouter un nouveau etudiant - Repondez par (0/1)");
    scanf("%i",&rep);
    dec = rep;
    if (dec != 0 )
    {
        (petu) = malloc(sizeof(Etudiant));
        p1->suivant = petu ;

    printf("Saisissez le numero de l'etudiant : ");
    gets(petu->numero);

    printf("Saisissez le nom de l'etudiant : ");
    gets(petu->nom);

    printf("Saisissez le prenom de l'etudiant : ");
    gets(petu->prenom);

    // Insertion de notes
    printf("Vouliez vous ajouter une nouvelle note - Repondez par (0/1)");
    scanf("%i",&rep1);
    dec1 = rep1;

    /// Saisit de la premiere note ou rien ------------------------------------------
    if (dec1==0)
    {
        petu->eval= NULL;
    }
    else  // On saisit la premiere note ...
    {
        (pnote) =  malloc(sizeof(Note));
        printf("Saisissez la note de l'etudiant : ");
        scanf("%d",&pnote->note);

        printf("Saisissez le coefficient de cette note : ");
        scanf("%d",&pnote->coef);

        petu->eval =pnote ;
        p2 = pnote ;

    }

    ///Saisir de la deuxienne note ----
    if(dec1 != 0)
    {

        dec1 ==0;
                //Saisir deuxiemem note
        printf("Vouliez vous ajouter une nouvelle note - Repondez par (0/1)");
        scanf("%i",&rep1);
        dec1 = rep1;
        if(dec==1)
        {
        (pnote) =  malloc(sizeof(Note));
        p2->suivant = pnote ;
        printf("Saisissez la note de l'etudiant : ");
        scanf("%d",&pnote->note);

        printf("Saisissez le coefficient de cette note : ");
        scanf("%d",&pnote->coef);

        p2 = pnote ;
        }

    }


    }

    /// FIn de saisie de note ------
    pnote->suivant = NULL;
        /// FIn de la saisie etudiant
    p1 = petu ;


    /// Fin de saisie etudiant
    petu->suivant = NULL ;



    /// Affichage de liste etudiant & note   ---------

// AFFICHER TOUS LES ENREGSTEMENTS
    p1 = tete;
    printf("LA LISTE SAISIE EST : \n");
    printf("\n");
    while (p1 != NULL)
    {
      p2 = p1->eval;
      printf("Numero : %s", p1->numero);
      printf("\n");
      printf("Nom : %s", p1->nom);
      printf("\n");
      printf("Prenom : %s", p1->prenom);
      //printf("\n");
      //printf("Moyenne : %2d", p1->moy);
      printf("\n");
      if (petu->eval != NULL   )
    {
        pnote=p1->eval;
        p2 = pnote;
        printf("Notes : %d (coef : %d )",p2->note,p2->coef);
        p2 = pnote->suivant;
        while (p2 !=NULL)
        {
            printf(", %d (coef : %d )",p2->note,p2->coef);
            pnote=p2;
            p2= pnote->suivant;
        };
       printf("\n");
    };
      p1 = p1->suivant;
      printf("================================================================");
      printf("\n");
    }
     printf("\n");
     printf("FIN DE LISTE : \n");
     printf("\n");

  /// Fin de affichage liste

/// AFFICHER FINISH

 ///Variables
    int totcoef;
    int totnote ;

    /// Debut

    petu = tete ;
    while (petu != NULL)
    {
        totcoef = 0 ;
        totnote = 0;
        pnote = petu->eval ;

        while (pnote != NULL)
        {
            totcoef = totcoef + pnote->coef ;
            totnote = totnote + pnote->note * pnote->coef ;
            p2 = pnote ;
            pnote =p2->suivant ;
        }
        if ( petu->eval != NULL)
        {
            petu->moy = totnote / totcoef ;
        }

    }

    // AFFICHER TOUS LES ENREGSTEMENTS
    p1 = tete;
    printf("LA LISTE SAISIE EST : \n");
    printf("\n");
    while (p1 != NULL)
    {
      p2 = p1->eval;
      printf("Numero : %s", p1->numero);
      printf("\n");
      printf("Nom : %s", p1->nom);
      printf("\n");
      printf("Prenom : %s", p1->prenom);
      printf("\n");
      printf("Moyenne : %i", p1->moy);
      printf("\n");

      p1 = p1->suivant;
      printf("================================================================");
      printf("\n");
    }
     printf("\n");
     printf("FIN DE LISTE : \n");

  /// Fin de affichage liste


/// FIn de fonction
}


void Calcul_moy(Pe tete)
{

    ///Variables
    int totcoef;
    float totnote ;

    /// Debut

    petu = tete ;
    while (petu != NULL)
    {
        totcoef = 0 ;
        totnote = 0;
        pnote = petu ->eval ;

        while (pnote != NULL)
        {
            totcoef = totcoef + pnote->coef ;
            totnote = totnote + pnote->note*pnote->coef ;
            p2 = pnote ;
            pnote =p2->suivant ;
        }
        if ( petu->eval != NULL)
        {
            petu->moy = totnote / totcoef ;
        }

    }

    // AFFICHER TOUS LES ENREGSTEMENTS
    p1 = tete;
    printf("LA LISTE SAISIE EST : \n");
    printf("\n");
    while (p1 != NULL)
    {
      p2 = p1->eval;
      printf("Numero : %s", p1->numero);
      printf("\n");
      printf("Nom : %s", p1->nom);
      printf("\n");
      printf("Prenom : %s", p1->prenom);
      //printf("\n");
      //printf("Moyenne : %2d", p1->moy);
      printf("\n");
      if (petu->eval != NULL   )
    {
        pnote=p1->eval;
        p2 = pnote;
        printf("Notes : %d (coef : %d )",p2->note,p2->coef);
        p2 = pnote->suivant;
        while (p2 !=NULL)
        {
            printf(", %d (coef : %d )",p2->note,p2->coef);
            pnote=p2;
            p2= pnote->suivant;
        };
       printf("\n");
    };
      p1 = p1->suivant;
      printf("================================================================");
      printf("\n");
    }
     printf("\n");
     printf("FIN DE LISTE : \n");

  /// Fin de affichage liste
}
int main()
{
      printf("Hello world!\n");
tete=NULL;

Inserer_Etudiant(tete);

Calcul_moy(tete) ;

}



-
Edité par EsaticSrit 29 octobre 2018 à 23:21:23

  • Partager sur Facebook
  • Partager sur Twitter
30 octobre 2018 à 6:58:51

Bonjour,

Déterrage

Citation des règles générales du forum :

Avant de poster un message, vérifiez la date du sujet dans lequel vous comptiez intervenir.

Si le dernier message sur le sujet date de plus de deux mois, mieux vaut ne pas répondre.
En effet, le déterrage d'un sujet nuit au bon fonctionnement du forum, et l'informatique pouvant grandement changer en quelques mois il n'est donc que rarement pertinent de déterrer un vieux sujet.

Au lieu de déterrer un sujet il est préférable :

  • soit de contacter directement le membre voulu par messagerie privée en cliquant sur son pseudonyme pour accéder à sa page profil, puis sur le lien "Ecrire un message"
  • soit de créer un nouveau sujet décrivant votre propre contexte
  • ne pas répondre à un déterrage et le signaler à la modération

Je ferme ce sujet. Me contacter par MP si besoin.

  • Partager sur Facebook
  • Partager sur Twitter

Pas d'aide concernant le code par MP, le forum est là pour ça :)