IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Comment incrémenter une valeur contenue dans tous les pères d'un nœud d'un arbre en temps constant ?


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 31
    Par défaut Comment incrémenter une valeur contenue dans tous les pères d'un nœud d'un arbre en temps constant ?
    Bonjour à tous.

    Je suis en train de développer en C++ un algorithme qui crée un arbre en temps linéaire (du nombre de feuilles).

    Chaque nœud de cet arbre contient actuellement un compteur qui doit être incrémenté à chaque fois qu'une opération sur l'un des fils dudit nœud est réalisée. Pour faire cette mise à jour, j'ai actuellement besoin de remonter tous les pères du nœud manipulé jusqu'à la racine pour incrémenter leurs compteurs. Le problème est que cette opération casse la complexité de mon algorithme et la transforme en O(n²) au lieu de O(n).

    Je cherche donc une solution raisonnable qui me permette, à chaque fois que je manipule un nœud, de changer en mémoire une seule valeur sur laquelle "pointent" tous les pères (et seulement eux, pas les fils) du nœud manipulé, de manière à ce que le fait de modifier cette valeur soit équivalent à incrémenter tous leurs compteurs d'un coup.

    D'après vous existe-il une telle solution svp ?

    Merci d'avance

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 153
    Billets dans le blog
    4
    Par défaut
    Salut,

    un pointeur du/des compteur(s) du/des père(s) chez les enfants ?
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    le problème, c'est que chaque père peut avoir plusieurs fils (puisque c'est un arbre)
    avoir un lien vers le pere peut servir, mais pas sur les compteurs de chaque pere.

    D'ailleurs, il devrait probablement y avoir une fonction qui augmente le lien du noeud courant, et s'appelle récursivement sur le père.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void inc() {
        ++compteur;
        pere->inc();
    }
    De toute facon, tu veux modifier tous les compteurs, il n'y a pas le choix, c'est N²
    Par contre, tu peux aussi ne pas modifier les pères, et au choix ne mettre à jour qu'après ou additionner les compteurs personnels.

  4. #4
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Normalement si c'est bien fait, ce sera plutôt du N⋅log(N) que du N²...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 31
    Par défaut
    Je ne sais pas exactement... En fait, le compteur compte pour chaque père le nombre de toutes les feuilles qui en sont issues (sachant qu'une fois une feuille créée on n'y touche plus), du coup pour l'instant je suis allé au plus simple et à chaque fois que je crée une feuille je parcours tous ses pères jusqu'à la racine et incrémente leurs compteurs un par un.

    Au début j'avais essayé de gérer les compteurs en additionnant les compteurs personnels comme préconise leternel, ça marche très bien dans mon algo naïf mais là j'implémente une adaptation de l'algorithme d'Ukkonen et ça marche beaucoup moins bien car l'algorithme "saute" d'une branche à l'autre quand il ajoute un nouveau nœud et peut ajouter ce nœud à n'importe quel niveau de la branche.

    Merci pour vos réponses.

  6. #6
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Est-ce que ton programme procède en deux temps: création des feuilles, puis utilisation du nombre de feuilles?

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 31
    Par défaut
    Du coup c'est pour ça que ça aurait été super bien d'avoir dans chaque fils quelque chose qui "pointe" sur tous ses pères à la fois, je l'aurais incrémenté à chaque création de feuille et ça aurait magiquement incrémenté d'un seul coup la bonne valeur pour tous ses pères

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 31
    Par défaut
    Oui en effet les compteurs ne sont utiles qu'après, pas lors de la création de l'arbre, donc s'il existe une manière optimale de les mettre à jour après la création de l'arbre (qui elle se fait en O(n)) c'est bien aussi.

  9. #9
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    en N, oui, mais en N = nombre de noeud, pas N = nombre de feuille.
    Tu pars de la racine, et pour chaque noeud, son nombre de feuilles est la somme du nombre de feuilles de chacun de ses fils + le nombre de fils qui sont des feuilles.

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 31
    Par défaut
    Du coup je l'ai fait de cette manière après avoir adapté Ukkonen (chaque noeud qui n'est pas une feuille a son compteur à zéro) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    unsigned int Noeud::calculerCompteurs() // calcule tous les compteurs à partir de la racine (à utiliser une seule fois et seulement à la racine dans l'algo opti)
    {
        unsigned int tailleFils = fils.size();
     
        for(unsigned int i = 0; i < tailleFils; i++)
        {
            compteur += fils[i].calculerCompteurs();
        }
     
        return compteur;
    }
    Je ne sais pas si c'est la meilleure méthode possible en complexité, mais ça marche.

  11. #11
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    C'est optimal, a un facteur constant près, car tu dois parcourir tes données.

  12. #12
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Et si tu te dépeches de remplacer la variable locale compteur par une donnée membre de ta classe, associée à un booléen évalué à true ou à false (selon qu'il faille effectivement compter les noeuds, ou que cela ait déjà été fait depuis le dernier ajout d'éléments), tant que le nombre d'enfants (et de descendants des enfants) n'a pas changé, tu ne devras même pas passer ton temps à parcourir à chaque fois tout ton arbre pour avoir la réponse

    (on appelle cela la "mise en cache" d'une information )

    Si tu n'as, effectivement, plus de modification au niveau des enfants (et des descendants) une fois que tu as fini de créer ton arbre, le "temps de calcul" (comprend : le fait d’exécuter cette boucle de manière récursive) sera rapidement amorti au travers de toutes les fois où... tu n'auras plus à le refaire (au dépends, il est vrai, de l'augmentation de "quelques bytes" de la taille requise pour représenter chaque noeud)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  13. #13
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    Et si tu te dépeches de remplacer la variable locale compteur par une donnée membre de ta classe, associée à un booléen évalué à true ou à false (selon qu'il faille effectivement compter les noeuds, ou que cela ait déjà été fait depuis le dernier ajout d'éléments), tant que le nombre d'enfants (et de descendants des enfants) n'a pas changé, tu ne devras même pas passer ton temps à parcourir à chaque fois tout ton arbre pour avoir la réponse
    En effet, et quand je vois ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    unsigned int Noeud::calculerCompteurs() // calcule tous les compteurs à partir de la racine (à utiliser une seule fois et seulement à la racine dans l'algo opti)
    {
        unsigned int tailleFils = fils.size();
     
        for(unsigned int i = 0; i < tailleFils; i++)
        {
            compteur += fils[i].calculerCompteurs();
        }
     
        return compteur;
    }
    Je me dis que tu mets en cache le nombre de fils/sous-fils lorsque tu ajoute ou supprimer un fils en remontant aux parents. Tu parcourras donc une fois à l'ajout/suppression de fils en remontant les parents et tu accéderas au nombre d'enfants en O1 car mise en cache.

Discussions similaires

  1. Réponses: 10
    Dernier message: 05/02/2008, 14h37
  2. Réponses: 3
    Dernier message: 22/11/2007, 17h02
  3. Réponses: 6
    Dernier message: 31/08/2007, 00h15
  4. Réponses: 4
    Dernier message: 29/03/2006, 08h22
  5. Comment afficher une valeur contenue dans une variable ?
    Par manubrard dans le forum Langage
    Réponses: 5
    Dernier message: 20/02/2006, 15h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo