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

Algorithmes et structures de données Discussion :

Réorganisation d'un arbre selon la chronologie des feuilles


Sujet :

Algorithmes et structures de données

  1. #1
    Membre régulier
    Homme Profil pro
    Manager de projet (retraité)
    Inscrit en
    Juillet 2010
    Messages
    150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Manager de projet (retraité)

    Informations forums :
    Inscription : Juillet 2010
    Messages : 150
    Points : 71
    Points
    71
    Par défaut Réorganisation d'un arbre selon la chronologie des feuilles
    Bonjour à tous,

    Je développe en Access VBA et je bute sur la difficulté algorithmique suivante. A partir d'une base de données je construis un arbre à l'aide de deux modules de classe:

    Classe Sommet:
    Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Option Compare Database
    Option Explicit
    Option Base 1
     
    Public lngIDSommet As Long
    Public intRank As Integer
    Public lngIDPere As Long, colFils As New Collection
     
    Property Let SetColFils(objNode As Sommet)
     colFils.Add objNode
    End Property
     
    Private Sub Class_Terminate()
     Set colFils = Nothing
    End Sub

    Classe Graphe :
    Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Option Compare Database
    Option Explicit
    Option Base 1
     
    Public colSommet As New Collection
    Public dicSommet As New Dictionary 'Collections des identifiants des sommets
     
    Private Sub Class_Terminate()
     dicSommet.RemoveAll
     Set colSommet = Nothing: Set dicSommet = Nothing
    End Sub

    Comme j'ai par ailleurs une relation de chronologie entre les feuilles de l'arbre, j'ai un traitement qui numérote celles-ci. Je stocke ce numéro dans la variable intRank des sommets de type feuille.

    Grâce à un parcours en largeur d'abord je peux numéroter les sommets de l'arbre de manière lexicographique (comme les n° de paragraphes en Word). Le pb c'est que je voudrais que cette numérotation respecte l'ordre des feuilles terminales comme le montrent les deux schémas suivants :

    Nom : Arbre1.JPG
Affichages : 188
Taille : 26,9 KoNom : Arbre2.JPG
Affichages : 184
Taille : 28,0 Ko

    Bref cela revient à actualiser le n° lexicographique en fonction de l'ordre qu'on veut (comme dans le mode Plan de Word).

    Si quelqu'un peut me suggérer une piste, cela me rendrait un grand service.

    Merci d'avance pour votre aide.

  2. #2
    Rédacteur/Modérateur

    Avatar de yahiko
    Homme Profil pro
    Développeur
    Inscrit en
    Juillet 2013
    Messages
    1 423
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 1 423
    Points : 8 700
    Points
    8 700
    Billets dans le blog
    43
    Par défaut
    Je ne suis pas sûr d'avoir saisi ton besoin, mais il semble qu'il s'agit simplement d'inverser récursivement toutes les branches de ton arbre.
    Ça peut se faire via ton parcours en largeur d'abord, par exemple.
    Tutoriels et FAQ TypeScript

  3. #3
    Membre régulier
    Homme Profil pro
    Manager de projet (retraité)
    Inscrit en
    Juillet 2010
    Messages
    150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Manager de projet (retraité)

    Informations forums :
    Inscription : Juillet 2010
    Messages : 150
    Points : 71
    Points
    71
    Par défaut Réorganisation d'un arbre selon la chronologie des feuilles
    Merci de t'intéresser à mon problème.

    Il ne s'agit pas d'inverser l'ordre des feuilles (le schéma volontairement simplifié a pu le laisser croire), il s'agit de piloter la numérotation de tous les sommets de l'arbre en cohérence avec la chronologie des feuilles.

    A mon sens le défaut de la récursivité c'est qu'il faut partir de la racine de l'arbre alors que les infos de base pour le tri sont aux extrémités.

  4. #4
    Rédacteur/Modérateur

    Avatar de yahiko
    Homme Profil pro
    Développeur
    Inscrit en
    Juillet 2013
    Messages
    1 423
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 1 423
    Points : 8 700
    Points
    8 700
    Billets dans le blog
    43
    Par défaut
    Dans ce cas, à vue de nez, je pense qu'il te faut des fonctions auxiliaires comme :

    Hauteur(nœud) --> hauteur du nœud dans l'arbre
    Frères(nœud) --> ensemble des nœuds ayant le même père
    Père(nœud) --> père du nœud
    Min(nœuds) --> nœud ayant l'ordre chronologique le plus faible parmi les autres nœuds

    Par rapport à ton exemple avec trois niveaux, la numérotation de chaque feuille est de la forme x.y.z, sachant que le nombre d'indices pour un nœud quelconque est égal à sa hauteur dans l'arbre.

    Il te faut donc déterminer la feuille F ayant l'ordre chronologique le plus petit.
    Les indices x, y et z de F vaut donc 1 (1.1.1).
    Cela implique que les frères de F ont les mêmes indices x et y qui valent 1 (1.1.z). Seul l'indice z change suivant leur ordre chronologique.
    Tu peux aussi en déduire la numérotation de tous les ascendants (père, grand-père, etc) de F.

    Une fois cela fait, tu peux t'attaquer aux cousins de F en remontant par le père de F puis les frères du père de F.
    En appliquant la même logique pour chaque cousin de F que celle appliquée pour F, tu peux en déduire la numérotation de toutes les feuilles de F et par extension de tous les nœuds de ton arbre.
    Tutoriels et FAQ TypeScript

  5. #5
    Membre régulier
    Homme Profil pro
    Manager de projet (retraité)
    Inscrit en
    Juillet 2010
    Messages
    150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Manager de projet (retraité)

    Informations forums :
    Inscription : Juillet 2010
    Messages : 150
    Points : 71
    Points
    71
    Par défaut Réorganisation d'un arbre selon la chronologie des feuilles
    OK, je regarde ça de près et ferai un retour sur ce qu'il en est.
    Merci et à bientôt.

  6. #6
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 054
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 054
    Points : 9 394
    Points
    9 394
    Par défaut
    Reste un point qui n'est pas clairement décrit dans l'énoncé.

    Dans ton illustration, les 2 fils de 1.2 sont D et E ; les 2 fils de 1.1 sont F et G ; il n'y a donc pas d'ambiguïté, 1.2 doit venir avant 1.1.

    Maintenant, imaginons cette configuration :
    1.2 a 2 fils : D et G ; 1.1 a 2 fils E et F
    Qui doit venir en premier ?

    On classe les individus selon l'âge des fils aînés ( D est plus âgé que F ... et donc 1.2 est avant 1.1)
    Ou bien on classe les individus selon l'âge des fils cadets ( G est plus jeune que F, et donc 1.2 est après 1.1)

    Il faudra arbitrer ce point avant de mettre en place la solution proposée par Yahiko.
    N'oubliez pas le bouton Résolu si vous avez obtenu une réponse à votre question.

  7. #7
    Rédacteur/Modérateur

    Avatar de yahiko
    Homme Profil pro
    Développeur
    Inscrit en
    Juillet 2013
    Messages
    1 423
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 1 423
    Points : 8 700
    Points
    8 700
    Billets dans le blog
    43
    Par défaut
    Même si je pense que la solution évoquée précédemment doit fonctionner, il me semble qu'un parcours récursif en largeur de ton arbre soit plus efficace pour (re)numéroter correctement tes nœuds.
    C'est de loin la solution la plus simple.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Numeroter(N: noeud, num: numerotation)
      N.numero := num
      Fils := TrierFils(N)
     
      Pour k = 1 à NbFils(N) Faire
        numFils := num || "." || k    // concaténation
        Numeroter(Fils[k], numFils)
      Fin Pour
    Fin Numeroter
    La fonction TrierFils() doit renvoyer un tableau des nœuds fils d'un nœud triés par ordre chronologique croissant.
    La fonction NbFils() doit renvoyer le nombre de fils d'un nœud

    Si tu appliques cette procédure Numeroter() sur la racine de ton arbre, alors, par construction, ta feuille ayant le plus petit ordre chronologique sera nécessairement numéroté 1.1. ... .1.
    Tutoriels et FAQ TypeScript

  8. #8
    Membre régulier
    Homme Profil pro
    Manager de projet (retraité)
    Inscrit en
    Juillet 2010
    Messages
    150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Manager de projet (retraité)

    Informations forums :
    Inscription : Juillet 2010
    Messages : 150
    Points : 71
    Points
    71
    Par défaut Réorganisation d'un arbre selon la chonologie des feuilles
    Merci à vous deux pour vos suggestions.

    J'ai terminé la mise au point et ça fonctionne parfaitement. Comme promis je reviens vers vous pour vous l'exposer.

    Rappel du problème :
    L'utilisateur :
    • décrit d'abord l'arbre dans un ordre quelconque,
    • définit ensuite la chronologie des feuilles en indiquant pour chacune d'elles ses prédécesseurs.

    Le système doit donc restructurer l'arbre et bâtir une numérotation lexicographique de tous les sommets.

    Principe de la solution :
    1. Je numérote les sommets (intRank) par un tri topologique du sous-graphe limité aux feuilles de l'arbre.
    2. Pour chaque ensemble de sommets de même père (donc une fratrie), j'indique au niveau du père le rang maxi de ses fils, et ceci étage par étage jusqu'au sommet. Pour réaliser cela j'utilise un parcours DFS postfixé en partant de la racine de l'arbre.
    3. La numérotation lexicographique est réalisée via un BFS dans lequel j'utilise une file de priorité de manière à traiter les rangs dans l'ordre croissant (je traite le somme qui a le rang minimal).


    Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    'Parcours en largeur pour calcul du code lexicographique des sommets de l'arbre
    Sub BFSwbs(ByRef objGraphe As Graphe)
     
    Dim colFile As New Collection, colWrk As New Collection
    Dim objCurr As Sommet, objSucc As Sommet
    Dim i As Integer, j As Integer, k As Integer
     
    'Réinitialisation des états de marquage
    For Each objCurr In objGraphe.colSommet
     i = i + 1
     objCurr.SetState = WHITE
    Next objCurr
     
    'On marque le sommet racine de l'arbre puis on le met dans la file
    With objGraphe: Set objCurr = .colSommet(.dicSommet(.lngIDRacine)): End With
    objCurr.SetState = BLACK: objCurr.strWBSCode = "1"
    colFile.Add objCurr
     
    'colFile est une file de priorité : on traite le sommet qui a le rang minimum
    While colFile.Count > 0
     j = MinRank(colFile): Set objCurr = colFile.Item(j): colFile.Remove (j)
     
     k = 0
     Set colWrk = objCurr.colSucc 'Collection annexe pour traitement par ordre croissant de rang
     While colWrk.Count > 0
      j = MinRank(colWrk): Set objSucc = colWrk(j): colWrk.Remove (j) 'ontraite le succseeur de rang minimal
     
      If objSucc.GetState = WHITE Then 'si ce successeur est non marqué
       objSucc.SetState = BLACK ' on le marque
       colFile.Add objSucc 'on le met dans la file
       k = k + 1
       'Le code WBS de ce successeur est égal au code WBS de son père auquel on ajoute le n° de séquence k
       objSucc.strWBSCode = objCurr.strWBSCode & "." & k
      End If
     Wend
    Wend
     
    Set colFile = Nothing: Set colWrk = Nothing
     
    End Sub

    Encore merci à vous tous.

    Bien cordialement.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Arbre N-aire avec des vecteurs de pointeurs
    Par valderama dans le forum Débuter
    Réponses: 3
    Dernier message: 15/01/2009, 16h42
  2. probleme d'arbre, evaluation des feuilles
    Par watiero dans le forum C++
    Réponses: 4
    Dernier message: 01/04/2008, 16h11
  3. Chronologie des enregistrements
    Par kelex dans le forum IHM
    Réponses: 6
    Dernier message: 12/03/2008, 09h54
  4. Erreur dans SELECT selon l'ordre des champs
    Par senacle dans le forum Requêtes
    Réponses: 2
    Dernier message: 07/03/2008, 12h06
  5. Réponses: 10
    Dernier message: 07/03/2006, 00h09

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