Partage
  • Partager sur Facebook
  • Partager sur Twitter

Structures de données : listes chainées

Sujet résolu
    23 mars 2020 à 7:57:52

    Slt tout d'abord voici mon code

    #include <stdio.h>
    #include <stdlib.h>
    #include "simple.h"
    
    /*---------------------------------------------------------------*/
    Liste *initialisation(void)
    {
    	Liste *liste = malloc(sizeof(Liste));
    	
    	if(liste == NULL)
    		exit(EXIT_FAILURE);
    	
    	liste->premier = NULL;
    	
    	return liste;
    }
    
    /*---------------------------------------------------------------*/
    Bool est_ce_vide(Liste *lst)
    {
    	if(lst->premier == NULL)
    			return vrai;
    	
    	return faux;
    }
    
    /*---------------------------------------------------------------*/
    void ajout_en_tete(Liste *lst, int nvnbr)
    {
    	Element *nouveau = malloc(sizeof(Element));
    	
    	if(lst == NULL || nouveau == NULL)
    		exit(EXIT_FAILURE);
    	
    	nouveau->nombre = nvnbr;
    	nouveau->suivant = lst->premier;
    	lst->premier = nouveau;
    }
    
    /*---------------------------------------------------------------*/
    void ajout_en_fin(Liste *lst, int nvnbr)
    {
    	Element *nouveau = malloc(sizeof(*nouveau));
    	
    	if(nouveau == NULL || lst == NULL)
    		exit(EXIT_FAILURE);
    	
    	if(est_ce_vide(lst))
    		ajout_en_tete(lst, nvnbr);
    
    	else
    	{
    		Element *tmp = lst->premier;
    		nouveau->nombre = nvnbr;
    		nouveau->suivant = NULL;
    		
    		while(tmp->suivant != NULL)
    			tmp = tmp->suivant;
    		
    		tmp->suivant = nouveau;
    	}
    }
    
    /*---------------------------------------------------------------*/
    void affiche_liste(Liste *lst)
    {
    	if(lst == NULL)
    		exit(EXIT_FAILURE);
    
    	if(est_ce_vide(lst))
    	{
    		printf("\nLa Liste est vide.\n");
    		exit(EXIT_SUCCESS);
    	}
    	
    	Element *actuel = lst->premier;
    	
    	while(actuel != NULL)
    	{
    		printf("[%d] ", actuel->nombre);
    		actuel = actuel->suivant;
    	}
    	
    	printf("\n");
    }
    
    /*---------------------------------------------------------------*/
    void suppression_en_tete(Liste *lst)
    {
    	if(lst == NULL)
    		exit(EXIT_FAILURE);
    
    	else if(!(est_ce_vide(lst)))
    	{
    		Element *elementASupprimer = lst->premier;
    		lst->premier = lst->premier->suivant;
    		free(elementASupprimer);
    	}
    }
    
    /*---------------------------------------------------------------*/
    void suppression_en_fin(Liste *lst)
    {
    	if(lst == NULL)
    		exit(EXIT_FAILURE);
    
    	if(!(est_ce_vide(lst)))
    	{
    		Element *elementASupprimer = lst->premier;
    		Element *precedent;
    			
    		while(elementASupprimer->suivant != NULL)
    		{
    			precedent = elementASupprimer;
    			elementASupprimer = elementASupprimer->suivant;
    		}
    		
    		precedent->suivant = NULL;
    		free(elementASupprimer);
    	}
    }
    
    /*---------------------------------------------------------------*/
    Element *recherche_element(Liste *lst, int valeur)
    {
    	if(lst == NULL)
    		exit(EXIT_FAILURE);
    
    	Element *tmp = lst->premier;
    	
    	while(tmp != NULL)
    	{
    		if(tmp->nombre == valeur)
    			return tmp;
    			
    		tmp = tmp->suivant;
    	}
    
    	return NULL;
    }
    
    /*---------------------------------------------------------------*/
    int nombre_occurence(Liste *lst, int valeur)
    {
    	int i = 0;
    	Element *element = lst->premier;
    	
    	if(lst == NULL)
    		exit(EXIT_FAILURE);
    	
    	while(element != NULL)
    	{
    		if(element->nombre == valeur)
    			i++;
    			
    		element = element->suivant;
    	}
    	
    	return i;
    }
    
    /*---------------------------------------------------------------*/
    void affiche_premier_element(Liste *lst)
    {
    	printf("\nLe premier element de la liste : [%d]\n", lst->premier->nombre);
    }
    
    /*---------------------------------------------------------------*/
    void affiche_dernier_element(Liste *lst)
    {
    	if(lst == NULL)
    		exit(EXIT_FAILURE);
    		
    	Element *tmp = lst->premier;
    	
    	while(tmp->suivant != NULL)
    	{
    		tmp = tmp->suivant;
    	}
    	
    	printf("\nLe dernier element de la liste : [%d]\n", tmp->nombre);
    }
    
    /*---------------------------------------------------------------*/
    Element *trouver_nieme_element(Liste *lst, int indice)
    {
    	if(lst == NULL || indice >= (taille_liste(lst)))
    		exit(EXIT_FAILURE);
    		
    	Element *tmp = lst->premier;
    	int i = 0;
    	
    	if(lst == NULL)
    			return NULL;
    
    	while(i < indice)
    	{
    		tmp = tmp->suivant;
    		i++;
    	}
    	
    	return tmp;
    }
    
    /*---------------------------------------------------------------*/
    int taille_liste(Liste *lst)
    {
    	int taille = 0;
    	
    	if(lst == NULL)
    		exit(EXIT_FAILURE);
    	
    	if(est_ce_vide(lst))
    			return 0;
    			
    	Element *tmp = lst->premier;
    	
    	while(tmp != NULL)
    	{
    		tmp = tmp->suivant;
    		taille++;
    	}
    	
    	return taille;
    }
    
    /*---------------------------------------------------------------*/
    void vider_liste(Liste *lst)
    {
    	if(lst == NULL)
    		exit(EXIT_FAILURE);
    		
    	int taille = taille_liste(lst);
    	
    	while(taille != 0)
    	{
    		suppression_en_tete(lst);
    		taille--;
    	}
    }
    
    /*---------------------------------------------------------------*/
    void suppression_du_i_element(Liste *lst, int indice)
    {
    	if(indice == 0)
    		exit(EXIT_FAILURE);
    
    	if(lst == NULL || indice >= (taille_liste(lst)))
    		exit(EXIT_FAILURE);
    	
    	Element *tmp = lst->premier;
    	Element *precedent;
    	
    	for(int i = 0; i < indice; i++)
    	{
    		precedent = tmp;
    		tmp = tmp->suivant;
    	}
    	
    	precedent->suivant = tmp->suivant;
    	free(tmp);
    }
    
    /*---------------------------------------------------------------*/
    void ajout_au_milieu(Liste *lst, int indice, int valeur)
    {
    	Element *nouveau = malloc(sizeof(Element));
    	
    	if(lst == NULL || nouveau == NULL || indice >= (taille_liste(lst)))
    		exit(EXIT_FAILURE);
    	
    	Element *tmp = lst->premier;
    	Element *precedent;
    	
    	for(int i = 0; i < indice; i++)
    	{
    		precedent = tmp;
    		tmp = tmp->suivant;
    	}
    	
    	nouveau->nombre = valeur;
    	nouveau->suivant = precedent->suivant;
    	precedent->suivant = nouveau;
    }
    
    /*---------------------------------------------------------------*/
    Liste *suppression_cible_valeur(Liste *lst, int valeur)
    {
    	if(lst == NULL)
    		exit(EXIT_FAILURE);
    		
    	Element *tmp = lst->premier;
    	Liste *nvliste = initialisation();
    	
    	while(tmp != NULL)
    	{
    		if(tmp->nombre != valeur)
    			ajout_en_fin(nvliste, tmp->nombre);
    			
    		tmp = tmp->suivant;
    	}
    	
    	vider_liste(lst);
    	
    	return nvliste;
    }
    
    /*Vous pouvez compléter votre bibliothèque avec des fonctions de tri,
    de recherche de minimum, de maximum et bien d'autre choses...*/

    Mon problème est que la fonction Liste *suppression_cible_valeur(Liste *lst, int valeur) si elle s'excecute très rapidement sur les listes de petites tailles , sur les grandes par contre le temps d'excecution est trop long (par exemple ~30s sur 100000). La fonction doit parcourir toute la chaine à la recherche de la valeur ciblé et en même temps copier les autres valeurs dans un autre liste et ensuite liberer l'ancienne liste avant de retourne la nouvelle . J'avoue je l'ai mal coder celle-là .Si vous pouvez m'aider à l'optimiser un peu se serait cool. 

    • Partager sur Facebook
    • Partager sur Twitter

    Nobody Is Anonyme!!!

      23 mars 2020 à 9:00:47

      Ça montre à l'évidence un problème de conception ! On ne fait pas n'importe quoi avec une liste chaînée, on peut s'en servir pour simuler des piles ou des files sinon, c'est inadapté.

      Ici tu t'en sers pour gérer des nombres.

      Il faudrait qu'elle soit triée en fonction de "nombre".

      Tu ajoutes un nombre en insérant un noeud  au bon endroit.

      Tu supprimes une valeur en supprimant le/les noeuds concernés.

      Jamais de recopies des bonnes valeurs, c'est justement ça l'intérêt des listes chaînées.

      Dernière choses, pour le dernier élément, tu as tout à fait le droit d'avoir un pointeur sur ce dernier élément, ça gagne énormément de temps.

      -
      Edité par joel76 23 mars 2020 à 9:03:13

      • Partager sur Facebook
      • Partager sur Twitter

      Le crayon la gomme et le papier sont les meilleurs outils du programmeur !

        23 mars 2020 à 9:33:19

        Ok merci beaucoup joel76 pour ta reponse.

        Voilà j'ai remanié le code mais le probléme maintenant est que j'ai un 0 qui s'affiche à la place de la valeur supprimée.

        Code:

        void suppression_cible_valeur(Liste *lst, int valeur)
        {
        	if(lst == NULL)
        		exit(EXIT_FAILURE);
        		
        	Element *tmp = lst->premier;
        	Element *precedent;
        	Element *suivant;
        	
        	while(tmp != NULL)
        	{
        		if(tmp->nombre == valeur)
        		{
        			precedent = tmp;
        			suivant = tmp->suivant;
        			free(tmp);
        			tmp = suivant;
        			precedent->suivant = suivant;
        		}
        		tmp = tmp->suivant;
        	}
        }

        resultat:

        Sur cette capture d'ecran j'ai supprimée la valeur 20 . Voyez le resultat.

        -
        Edité par BamAss 23 mars 2020 à 10:04:29

        • Partager sur Facebook
        • Partager sur Twitter

        Nobody Is Anonyme!!!

          23 mars 2020 à 11:33:40

          Quand on supprime un noeud, on doit mémoriser le "père" du noeud, et relier père->suivant à noeud->suivant   (je me demande si je suis clair ?!).

          -
          Edité par joel76 23 mars 2020 à 11:42:36

          • Partager sur Facebook
          • Partager sur Twitter

          Le crayon la gomme et le papier sont les meilleurs outils du programmeur !

            23 mars 2020 à 12:31:56

            Je pense bien que c'est ce que j'ai fait dans mon precedent code. Cependant d'où vient l'erreur?
            • Partager sur Facebook
            • Partager sur Twitter

            Nobody Is Anonyme!!!

              23 mars 2020 à 13:55:43

              Ben non. Il faut tester  tmp->suivant->nombre et non pas tmp->nombre
              • Partager sur Facebook
              • Partager sur Twitter

              Le crayon la gomme et le papier sont les meilleurs outils du programmeur !

                23 mars 2020 à 14:11:30

                Qu'arrive-t-il si tu supprimes le premier élément de ta liste?
                Tu ne dis pas à ta liste que le premier est le suivant du premier.
                Tu ne dois pas modifier precedent avant de faire le free() car le précédent n'est pas l'élément que tu vas supprimer.
                Faire un tri avec une liste simplement chaînée est pénible et peu efficace.
                Une liste doublement chaînée est plus efficace car on peu reculer plus facilement.
                De toute façon, les tris avec des listes chaînées ne sont pas la meilleure idée, même avec un bon algorithme.

                -
                Edité par PierrotLeFou 23 mars 2020 à 14:19:23

                • Partager sur Facebook
                • Partager sur Twitter

                Le Tout est souvent plus grand que la somme de ses parties.

                  23 mars 2020 à 14:31:14

                  Oui mais comme je suis en apprentissage, je me dis que maitriser les listes simplement chainées avant de passer aux doublement chainées serait plus avantageux que je de sauter directement à la suite

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Nobody Is Anonyme!!!

                    23 mars 2020 à 16:26:58

                    Je suis d'accord que tu dois maîtriser les listes simplement chaînées en premier.
                    Si tu supprimes le premier élément de ta liste, tu le sais et tu agit en conséquence.
                    Mais si tu ne sais pas où se trouve l'élément à supprimer dans ta liste, il faut que tu vérifies que:
                    + soit la liste ne contient qu'un seul élément.
                    + que tu supprimes le premier élément sans le savoir.
                    Pour cela, tu dois tester si l'élément à supprimer (tmp) est égal à lst->premier (tu testes les pointeurs).
                    Si c'est le cas, tu dois faire lst->premier = tmp->suivant
                    Sinon, tu dois faire precedent->suivant = tmp->suivant
                    et les deux avant le free()
                    et à ce stade, ce n'est pas important si ce suivant est NULL.
                    Si tu dois supprimer plusieurs éléments dans ta liste, il ne faut pas modifier precedent tout de suite car il est toujours le précédent du suivant de ce que tu viens de supprimer.
                    (est-ce assez clair? ... :) )
                    Tu ne dois en aucun cas te fier au contenu de l'élément que tu viens de libérer avec free().

                    -
                    Edité par PierrotLeFou 23 mars 2020 à 16:29:10

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Le Tout est souvent plus grand que la somme de ses parties.

                      23 mars 2020 à 19:14:07

                      joel76 a écrit:

                      Ben non. Il faut tester  tmp->suivant->nombre et non pas tmp->nombre


                      Je cite cette phrase car c'est elle la clé du problème. Faire un petit dessin pour bien comprendre.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        24 mars 2020 à 1:01:46

                        Voici ma version de la fonction:
                        -
                        void suppression_cible_valeur(Liste *lst, int valeur)
                        {
                            if(lst == NULL)
                                exit(EXIT_FAILURE);
                            Element *tmp = lst->premier;
                            Element *suivant;
                            Element *precedent; // sera défini au premier élément différent
                            while(tmp != NULL)
                            {
                                if(tmp->nombre == valeur)
                                {
                                    if(lst->premier == tmp) // si on doit supprimer le premier
                                        lst->premier = tmp->suivant;
                                    else // si on doit en supprimer un autre
                                        precedent->suivant = tmp->suivant;
                                    suivant = tmp->suivant;
                                    free(tmp);
                                    tmp = suivant;
                                }
                                else // si on n'a pas besoin de supprimer
                                {
                                    precedent = tmp;
                                    tmp = tmp->suivant;
                                }
                            }
                        }

                        -
                        Edité par PierrotLeFou 24 mars 2020 à 1:29:01

                        • Partager sur Facebook
                        • Partager sur Twitter

                        Le Tout est souvent plus grand que la somme de ses parties.

                          24 mars 2020 à 15:46:26

                          Slt merci beaucoup pour vos explications et PierrotLeFou pour ton code je l'ai testé en il marche. Dites comment faites vous pour etre aussi bon en programmation ?
                          • Partager sur Facebook
                          • Partager sur Twitter

                          Nobody Is Anonyme!!!

                            24 mars 2020 à 16:49:39

                            » pour ton code je l'ai testé en il marche. Dites comment faites vous pour etre aussi bon en programmation ?
                            On ne devient pas bon en programmation en 3 jours.
                            La plupart d'entre nous ont plusieurs années d'expérience.
                            Personnellement, je fais du C depuis environ 10 ans, et le reste (...) depuis environ 30 ans.
                            • Partager sur Facebook
                            • Partager sur Twitter

                            Le Tout est souvent plus grand que la somme de ses parties.

                              24 mars 2020 à 18:39:33

                              Il va me falloir alors pas mal de temps pour vraiment être un as et maitriser vraiment le langage. Ça tombe bien alors je suis passionné et motivé.
                              • Partager sur Facebook
                              • Partager sur Twitter

                              Nobody Is Anonyme!!!

                                25 mars 2020 à 2:10:24

                                Si tu veux occuper ton temps durant la période de confinement, tu pourrais tester ma fonction.
                                + essaies avec une liste vide.
                                + essaies avec une liste ne contenant qu'un élément (testes en essayant avec l'élément ou un qui ne se trouve pas dans la liste).
                                + mets plusieurs fois la même valeur dans ta liste et essaies de tous les éliminer.
                                + mets uniquement plusieurs occurences d'une valeur dans la liste et essaies de l'éliminer.
                                Tu connais le proverbe «c'est en forgeant qu'on devient forgeron»

                                -
                                Edité par PierrotLeFou 25 mars 2020 à 4:44:10

                                • Partager sur Facebook
                                • Partager sur Twitter

                                Le Tout est souvent plus grand que la somme de ses parties.

                                  25 mars 2020 à 8:31:49

                                  Slt,

                                  Pour ce qui est de ta première consigne il ne passe rien quand j'essaie de supprimer une liste vide , du moins en apparence.

                                  Pour la seconde , en testant avec un seul élément celui si est simplement retiré de la liste et la fonction affiche_liste me signale que la liste est vide. Et pour ce qui est supprimer un élément qui ne se trouve pas dans la liste, j'ai pas non plus d'erreur de ce côté.

                                  Pour les troisième et quatrième consignes , toutes les occurences de la valeur ciblée sont simplement retirées de la liste. Pour le premier cas , la fonction affiche_liste m'affiche ce qui reste de la liste et pour le deuxième elle me signale que la liste est vide.

                                  -
                                  Edité par BamAss 25 mars 2020 à 10:30:28

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  Nobody Is Anonyme!!!

                                    25 mars 2020 à 16:00:23

                                    C'est très bien. Ça te donne une petite idée de la façon dont on peut tester des fonctions.
                                    Comme je le dis, tester les cas limites et les cas exotiques.
                                    • Partager sur Facebook
                                    • Partager sur Twitter

                                    Le Tout est souvent plus grand que la somme de ses parties.

                                      25 mars 2020 à 17:06:04

                                      Je signale le site HackerRank qui propose des exercices d'algo à résoudre dans presque tous les langages. Ça peut être intéressant.

                                      En C, il y a toute une série d'exo sur les listes chaînées.

                                      • Partager sur Facebook
                                      • Partager sur Twitter

                                      Le crayon la gomme et le papier sont les meilleurs outils du programmeur !

                                        25 mars 2020 à 17:26:38

                                        J'y est jetté un coup d'oeil et il est super ce site. Je l'ajoute direct à mes favoris. Merci beaucoup.

                                        -
                                        Edité par BamAss 25 mars 2020 à 17:38:12

                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Nobody Is Anonyme!!!

                                        Structures de données : listes chainées

                                        × 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