Structure récursive & Hiérarchie

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Structure récursive & Hiérarchie

Message par falsam »

Une structure qui fait référence à elle même pour former une liste de nodes. C'est cette astuce qu'on utilisera pour arriver à établir un exemple de hiérarchie.

Principe de fonctionnement.
Un node peut contenir une ou plusieurs variables ainsi qu'une liste de nodes.
Chacun de ces nodes de la liste contiendra une liste de nodes.
Chacun de ces nodes de la liste contiendra une liste de nodes.
etc ...

Code : Tout sélectionner

Structure NewNode
  Texte.s
  List Nodes.NewNode()
EndStructure
Global NewList Nodes.NewNode()
Exemple.
Nous allons créer des types de véhicules (terrestres & marins). Pour chacun des types on va inséré des véhicules et sur un des véhicules nous allons insérer une motorisation.

Code : Tout sélectionner

Structure NewNode
  Texte.s
  List Nodes.NewNode()
EndStructure
Global NewList Nodes.NewNode()

Procedure AddNode(Texte.s,*Node.NewNode=0)
  Protected Result
  
  If *Node
    Result = AddElement(*Node\Nodes())
    *Node\Nodes()\Texte = Texte
  Else
    Result = AddElement(Nodes())
    Nodes()\Texte = Texte
  EndIf   
  ProcedureReturn Result 
EndProcedure

Procedure ListNodes(List Nodes.NewNode())
  Static pre.s = "="
  ForEach Nodes()
    Debug pre + "> " + Nodes()\Texte  
    ForEach Nodes()\Nodes()
      pre + "="
      ListNodes(Nodes()\Nodes())
    Next
  Next
  pre = "="
EndProcedure

;// Test Zone

; Création de la hiérachie 
Terrestre = AddNode("Véhicules terrestres")

AddNode("Trotinettes", Terrestre)
AddNode("Vélos", Terrestre)

Voitures = AddNode("Voitures", Terrestre)

AddNode("Electriques", Voitures)
AddNode("Thermiques ", Voitures)

Marins = AddNode("Véhicules marins")
AddNode("Barques", Marins)
AddNode("Voiliers", Marins)
AddNode("Paquebots", Marins)

; Visualisation du résultat
ListNodes(Nodes())
le résultat devrait être le suivant.
=> Véhicules terrestres
==> Trotinettes
==> Vélos
==> Voitures
===> Electriques
===> Thermiques
=> Véhicules marins
==> Barques
==> Voiliers
==> Paquebots
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Structure récursive & Hiérarchie

Message par falsam »

Représentation visuelle de la hiérarchie. (Dessin classique dans un canvas)

Code : Tout sélectionner

EnableExplicit

Structure NewNode
  Texte.s
  x.i
  y.f
  List Node.NewNode()
EndStructure
Global NewList Nodes.NewNode()

Global rx, ry, nx0, ny0, nx1, ny1 

;Plan de l'application
Declare Start()
Declare AddNode(Texte.s, x.i, y.i, *Node.NewNode=0)
Declare Draw(List Nodes.NewNode())
Declare Exit()

Start()

Procedure Start()
  Protected Value, ww = 800, wh = 700
  
  OpenWindow(0, 0, 0, ww, wh, "Structure recursive et hierachie", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  CanvasGadget(0, 0, 0, ww, wh)
  
  ; Création de la hiérachie
  Value = AddNode("Véhicules terrestres", 100, 50)
  AddNode("Trotinettes", 300, 150, Value)
  
  Value = AddNode("Voitures", 250, 250, Value)
  AddNode("Electriques", 500, 350, Value)
  AddNode("Thermiques", 400, 400, Value)
  
  Value = AddNode("Marins", 100, 450)
  AddNode("Barques", 400, 520, Value)
  AddNode("Voiliers", 330, 580, Value)
  AddNode("Paquebots", 230, 630, Value)
  
  ; Dessin des nodes 
  If StartDrawing(CanvasOutput(0))  
    Box(0, 0, ww, wh, RGB(211, 211, 211))
    Draw(Nodes())
    StopDrawing()
  EndIf
  
  ;Triggers
  BindEvent(#PB_Event_CloseWindow, @Exit())
  
  Repeat : WaitWindowEvent() : ForEver
EndProcedure

Procedure AddNode(Texte.s, x.i, y.i, *Node.NewNode=0)
  Protected Result
  
  If *Node
    Result = AddElement(*Node\Node())
    *Node\Node()\Texte = Texte
    *Node\Node()\x = x
    *Node\Node()\y = y
  Else
    Result = AddElement(Nodes())
    Nodes()\Texte = Texte
    Nodes()\x = x
    Nodes()\y = y   
  EndIf   
  ProcedureReturn Result 
EndProcedure

Procedure Draw(List Nodes.NewNode())   
  Static First 
  
  ForEach Nodes()        
    nx1 = Nodes()\x
    ny1 = Nodes()\y
    
    DrawingMode(#PB_2DDrawing_Default)
    Box(nx1, ny1, 200, 30, RGB(255, 215, 0))
    
    DrawingMode(#PB_2DDrawing_Outlined)
    Box(nx1, ny1, 200, 30, RGB(0, 0, 0))
    
    DrawingMode(#PB_2DDrawing_Transparent)
    DrawText(nx1 + 5 , ny1 + 5, Nodes()\Texte, RGB(0, 0, 0))
    
    If First = 0
      rx = Nodes()\x
      ry = Nodes()\y
      First = #True
    Else
      LineXY(nx0 + 100, ny0 + 30, nx1 + 100 , ny1, RGB(105, 105, 105)) 
      Circle(nx0 + 100, ny0 + 30 , 4, RGB(0, 0, 0))
      Circle(nx1 + 100, ny1, 4, RGB(0, 0, 0))      
    EndIf
    
    ForEach Nodes()\Node()
      nx0 = Nodes()\x
      ny0 = Nodes()\y
      Draw(Nodes()\Node())
    Next  
  Next
  
  ; Retour racine de l'arbre 
  nx0 = rx
  ny0 = ry
EndProcedure

Procedure Exit()  
  End
EndProcedure
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Structure récursive & Hiérarchie

Message par falsam »

Représentation visuelle de la hiérarchie. (Dessin vectoriel dans un canvas)

Code : Tout sélectionner

EnableExplicit

Structure NewNode
  Texte.s
  x.i
  y.f
  List Node.NewNode()
EndStructure
Global NewList Nodes.NewNode()

Global rx, ry, nx0, ny0, nx1, ny1 

;Plan de l'application
Declare Start()
Declare AddNode(Texte.s, x.i, y.i, *Node.NewNode=0)
Declare Draw(List Nodes.NewNode())
Declare Exit()

Start()

Procedure Start()
  Protected Value, ww = 800, wh = 700
  
  OpenWindow(0, 0, 0, ww, wh, "Structure recursive et hierachie", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  CanvasGadget(0, 0, 0, ww, wh)
  
  ; Création de la hiérachie  
  Value = AddNode("Véhicules terrestres", 100, 50)
  AddNode("Trotinettes", 300, 150, Value)
  
  Value = AddNode("Voitures", 250, 250, Value)
  AddNode("Electriques", 500, 350, Value)
  AddNode("Thermiques", 400, 400, Value)
  
  Value = AddNode("Marins", 100, 450)
  AddNode("Barques", 400, 520, Value)
  AddNode("Voiliers", 330, 580, Value)
  AddNode("Paquebots", 230, 630, Value)
  
  ; Dessin des nodes 
  If StartVectorDrawing(CanvasVectorOutput(0))  
    LoadFont(0, "Arial", 10, #PB_Font_Bold)
    VectorFont(FontID(0), 15)
    AddPathBox(0, 0, ww, wh)
    VectorSourceColor(RGBA(211, 211, 211, 255))
    FillPath()      
    Draw(Nodes())
    StopVectorDrawing()
  EndIf
  
  ;Triggers
  BindEvent(#PB_Event_CloseWindow, @Exit())
  
  Repeat : WaitWindowEvent() : ForEver
EndProcedure

Procedure AddNode(Texte.s, x.i, y.i, *Node.NewNode=0)
  Protected Result
  
  If *Node
    Result = AddElement(*Node\Node())
    *Node\Node()\Texte = Texte
    *Node\Node()\x = x
    *Node\Node()\y = y
  Else
    Result = AddElement(Nodes())
    Nodes()\Texte = Texte
    Nodes()\x = x
    Nodes()\y = y   
  EndIf   
  ProcedureReturn Result 
EndProcedure

Procedure Draw(List Nodes.NewNode())   
  Static First 
  Protected Delta = 30
  
  ForEach Nodes()        
    nx1 = Nodes()\x
    ny1 = Nodes()\y
    
    ; Dessin de la boite et du texte
    AddPathBox(nx1, ny1, 200, 30)
    VectorSourceColor(RGBA(255, 215, 0, 255))
    FillPath()
    
    AddPathBox(nx1, ny1, 200, 30)
    VectorSourceColor(RGBA(0, 0, 0, 255))
    StrokePath(3)
        
    MovePathCursor(nx1 + 5, ny1 + 5)   
    AddPathText(Nodes()\Texte)
    VectorSourceColor(RGBA(0, 0, 0, 255))
    FillPath()
    
    ; Dessin de la ligne (Courbe de Bezier)
    If First = 0
      rx = Nodes()\x
      ry = Nodes()\y
      First = #True
    Else
      MovePathCursor(nx0 + 100, ny0 + 30)
      AddPathCurve(nx0 - Delta + 100 , ny0 + Delta + 30, nx1 + Delta + 100, ny1 - Delta + 30, nx1 + 100, ny1) 
      
      VectorSourceColor(RGBA(255, 0, 0, 255))
      StrokePath(3)
      
      ; Dessin des plots de jonction
      AddPathCircle(nx0 + 100, ny0 + 30 , 4)
      VectorSourceColor(RGBA(0, 0, 0, 255))
      FillPath()
      
      AddPathCircle(nx1 + 100, ny1, 4)
      VectorSourceColor(RGBA(0, 0, 0, 255))
      FillPath()     
    EndIf
    
    ForEach Nodes()\Node()
      nx0 = Nodes()\x
      ny0 = Nodes()\y
      Draw(Nodes()\Node())
    Next  
  Next
  
  ; Retour racine de l'arbre 
  nx0 = rx
  ny0 = ry
EndProcedure

Procedure Exit()  
  End
EndProcedure
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
venom
Messages : 3072
Inscription : jeu. 29/juil./2004 16:33
Localisation : Klyntar
Contact :

Re: Structure récursive & Hiérarchie

Message par venom »

8O Merci falsam pour les exemples. Il y a pas a dire, j'ai du mal a saisir les structures (pourtant j'en croise souvent) mais qu'est ce que c'est pratique.

Je vais étudié tout ça.






@++
Windows 10 x64, PureBasic 5.73 x86 & x64
GPU : radeon HD6370M, CPU : p6200 2.13Ghz
Avatar de l’utilisateur
Micoute
Messages : 2522
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: Structure récursive & Hiérarchie

Message par Micoute »

Du très bon travail comme j'aime, merci pour ce partage falsam.
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 5.73 PB 6.00 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Avatar de l’utilisateur
Zorro
Messages : 2185
Inscription : mar. 31/mai/2016 9:06

Re: Structure récursive & Hiérarchie

Message par Zorro »

ou comme ça :mrgreen: :lol: :lol: :lol: :lol:

Code : Tout sélectionner




Declare ajout(type.s,level)

Enumeration
		#Win 
		#tree 
EndEnumeration

If OpenWindow(#win, 0, 0, 250, 400, "liste de vehicules", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) 
		TreeGadget(#tree, 10, 10, 200, 350)
		ajout("terrestre",0)
		;
		ajout("Voiture",1)
		ajout("Electrique",2)
		ajout("Thermique",2)
		;
		ajout("Trotinette",1)
		;
		ajout("Velo",1)
		ajout("Panier pick_nick",2)
		;
		ajout("Marin",0)
		;
		ajout("Barque",1)
		ajout("Canoée hooo héééé",1)
		ajout("voilier",1)
		ajout("Paquebot",1)
		Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
procedure ajout(type.s,level)
		AddGadgetItem(#tree, -1, type.s, 0, level) ; si vous souhaitez ajouter une image, utilisez 
EndProcedure
Image
Image
Site: http://michel.dobro.free.fr/
Devise :"dis moi ce dont tu as besoin, je t'expliquerai comment t'en passer"
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Structure récursive & Hiérarchie

Message par falsam »

Oui bien sur Zorro ! Tu le sens bien le HS ?

L'objectif n'est pas de créer un treeview mais de manipuler une structure récursive hierachique. La liste obtenue pouvant être sauvegardée au format JSON en moins de 5 lignes de code et loader par la suite là aussi en quelques lignes.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Zorro
Messages : 2185
Inscription : mar. 31/mai/2016 9:06

Re: Structure récursive & Hiérarchie

Message par Zorro »

tain ... j'avais pourtant pas lésiné sur le nombre de smiley .. :roll:
Image
Image
Site: http://michel.dobro.free.fr/
Devise :"dis moi ce dont tu as besoin, je t'expliquerai comment t'en passer"
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Structure récursive & Hiérarchie

Message par djes »

Très chouette ! Merci ! :D
Avatar de l’utilisateur
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Structure récursive & Hiérarchie

Message par Kwai chang caine »

C'est drôlement chouette, merci Falsam 8)
J'ai pas trop compris à quoi ça sert, je suppose pour la représentation graphique d'une hiérarchie, ou bien tu bosses sur ça car ça fait partie d'un projet :?:
C'est drôlement chouette ce que vous faites tous en ce moment sur ce style de sujet....y'a une épidémie :mrgreen:
Zorro a écrit :tain ... j'avais pourtant pas lésiné sur le nombre de smiley .. :roll:
Effectivement 8O ....m'en parlez pas mon bon m'sieur...à notre époque même l’efficacité des smyley par en couille..... :| :lol:
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Shadow
Messages : 1373
Inscription : mer. 04/nov./2015 17:39

Re: Structure récursive & Hiérarchie

Message par Shadow »

Je pense que ça pourrais me servir à moi un jours car dans mon logiciel j'utilise justement ce genre de chose.

Un Gadget peut avoir des enfants, les enfants peuvent avoir aussi des enfants, qui eux même peuvent avoir des enfants, etc etc etc...
Ex:

Fenêtre
> PanelGadget
>> Panel 1
>>> TreeView
>>>> Lien n°1
>>>>> Enfants n°1
>>>>>> Petit Enfants n°1
>>>>> Enfants n°2
>>>>>> Petit Enfants n°1
>>>>>> Petit Enfants n°2
>>>>> Enfants n°3
>>>> Lien n°2
>>>> Lien n°3
>> Panel 2
> Bouton

Sachez que ça peut aller très loin comme ça dans la Hiérarchie, dans mon logiciel, je gère n'importe quel niveau de Hiérarchie comme ça !
Une fois qu'on à compris, c'est pas si compliquer.

Pour parcourir les élément et leurs enfants, ont utilise une procédure récursive !
Merci Falsam pour ton exemple très utile :)
Processeur: Intel Core I7-4790 - 4 Cœurs - 8 Thread: 3.60 Ghz.
Ram: 32 GB.
Disque: C: SDD 250 GB, D: 3 TB.
Vidéo: NVIDIA GeForce GTX 960: 2 GB DDR5.
Écran: Asus VX248 24 Pouces: 1920 x 1080.
Système: Windows 7 64 Bits.

PureBasic: 5.60 x64 Bits.
G-Rom
Messages : 3627
Inscription : dim. 10/janv./2010 5:29

Re: Structure récursive & Hiérarchie

Message par G-Rom »

Je vais critiquer en argumentant ton code.
- Véhicules terrestre -> Marin -> voiliers , bon celle la elle est facile.

Sans déconner , ta structure "est trop rigide", il est parfois utile de connaitre pour X ou Y raison le parent d'un noeud.
tu pourrais utilisé ceci :
Structure NewNode
Texte.s
x.i
y.f
List Node.NewNode()
*Parent.NewNode
EndStructure
Il faut bien entendu que cela soit un pointeur sur le parent, je sais que si tu veut sauvegardé dans un json, le pointeur ne sert à rien, dans ce cas, tu l'ignore. si tu n'utilise pas de pointeur , tu auras un "nouveau" node à part entière.
Idem , pour les enfants, j'utiliserais des pointeurs à la place , là , tu donnes la responsabilité à NewNode la gestion des enfants, si tu détruit un parent , tout les enfants sont morts aussi, pas très flexible.
Je pense aussi que ce n'est pas très "cache friendly" , c'est à dire qu'au niveau optimisation , ce n'est pas contiguë , avec 3 nodes pas de problèmes , mais si tu en as des milliers , ca peu se faire ressentir dans les accès mémoire.
je ne dit pas que c'est mal, mais , ça manque de flexibilité pour être utilisé.
J'avais fait un "topo" à shadow la dessus justement y a quelque temps : https://www.purebasic.fr/french/viewtop ... 38#p204138 , si cela peut être utile.
Je sais que tu vas me parler que pour sauvegardé , du coup avec les pointeurs on perd la hiérarchie , ce qui est logique , mais sois tu sauvegardes sans te soucier des pointeurs , ou soit tu utilises , comme d'autres le font , un système de "path"

Par exemple, par rapport à ton graph , "Electrique" aura le path suivant : Véhicules terrestres/Voitures/Electrique , évidement cela implique que des noeuds du même niveau n'ai pas le même nom...
Voilà, j'éspère avoir été constructif & compréhensible. si ce n'est pas le cas , n'hésite pas à me posé des questions.

@++
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Re: Structure récursive & Hiérarchie

Message par Ollivier »

C'est un leurre, c'est pas possible. Remarque : un débat hiérarchique sans fin, c'est récursif.

Pour rester constructif : exemple de récursivité

Un autre exemple : ta retraite, inlassablement travaillée et retravaillée de manière récursive sur les marchés financiers (comme x retraites, salaires d'Etat ou indemnités).

Par contre, la présentation est nickel.

Code : Tout sélectionner

véhicule
   aérien
      delta
      cape
      montgolfière
      dirigeable
   terrestre
      simple
         calèche
         traineau
      composé
         patins
   maritime
      simple
         péniche
            propulsion Diesel
            traction à cheval
         zodiaque
            rames
            moteur thermique
            turboréacteur
      composé
         catamaran
G-Rom
Messages : 3627
Inscription : dim. 10/janv./2010 5:29

Re: Structure récursive & Hiérarchie

Message par G-Rom »

Ollivier a écrit :C'est un leurre, c'est pas possible. Remarque : un débat hiérarchique sans fin, c'est récursif.

Pour rester constructif : exemple de récursivité

Un autre exemple : ta retraite, inlassablement travaillée et retravaillée de manière récursive sur les marchés financiers (comme x retraites, salaires d'Etat ou indemnités).

Par contre, la présentation est nickel.

Code : Tout sélectionner

véhicule
   aérien
      delta
      cape
      montgolfière
      dirigeable
   terrestre
      simple
         calèche
         traineau
      composé
         patins
   maritime
      simple
         péniche
            propulsion Diesel
            traction à cheval
         zodiaque
            rames
            moteur thermique
            turboréacteur
      composé
         catamaran
C'est moi, ou je ne comprends rien ? y a un topic intéressant , puis après des références sur le jardinage en timelapse , des phrases énigmatiques , de la politique de comptoir , etc...
c'est un leurre ? tu réponds à qui ? à quoi ? qu'est ce qui n'est pas possible ?
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Re: Structure récursive & Hiérarchie

Message par Ollivier »

C'est pas grave. Falsam a corrigé.
Répondre