Poster une réponse  Créer un sujet 
[Algoritmie] Parcours d'une hiérarchie
Auteur Message
CrazyCat
Administrator
*******


Messages : 130
Groupe : Administrateurs
Inscription : Feb 2007
Statut : Absent
Réputation : 0
Message : #1
[Algoritmie] Parcours d'une hiérarchie

Lorsqu'on veut représenter une hiérarchie (une arborescence), la méthode la plus couramment utilisée est la structure par auto-jointure, c'est à dire avec une relation parent/enfant.


Représentation graphique de l'arborescence

S'il est facile de trouver le parent d'un élément ou les élements enfants de premier niveau avec des requètes simples, ça se complique énormément sitôt que l'on veut aller à des niveaux plus bas, il faut utiliser des requètes récursives qui ne peuvent pas être mises en place partout.
Ce système de classification est donc à proscrire si au moins l'une des conditions ci-dessous est vérifiée:
  • l'arbre est profond (plus de 5 niveaux)
  • l'arbre est large (plus de 100 éléments sur un même niveau)
  • l'arbre contient beaucoup de valeurs (à partir de 200 à 300 éléments)
  • la majorité des requêtes sont des requêtes d'interrogation - SELECT (au moins 50% des requêtes)

Il existe une seconde méthode qui nécessite un peu plus de travail pour la modélisation mais qui s'avère payante sitôt qu'on en a pris l'habitude: la représentation intervallaire.

Le principe est de donner à chaque élément ses bornes "gauche" et "droite". L'attribution des valeurs de ces bornes se fait en parcourant l'arbre comme si l'on traçait une ligne pour l'entourer au plus près sans jamais croiser cette ligne avec une branche et en numérotant séquentiellement chaque feuille ou nœud une première fois par le bord gauche et une seconde fois par le bord droit.


Représentation graphique de l'arborescence


On peut aussi représenter cette nouvelle arborescence sous forme de "tranches":


Représentation par tranches


Voici la requète de création (et de remplissage) de la table représentant cette structure:
Code SQL :
CREATE TABLE NEW_FAMILLE (
   NFM_BG INTEGER,
   NFM_BD INTEGER,
   NFM_LIB VARCHAR(16)
)

INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (1, 44, 'Transport')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (2, 21, 'Aérien')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (3, 4, 'Planeur')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (5, 6, 'Parachute')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (7, 8, 'Hélico')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (9, 10, 'Fusée')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (11, 12, 'ULM')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (13, 20, 'Avion')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (14, 15, 'Militaire')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (16, 17, 'Tourisme')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (18, 19, 'Civil')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (22, 35, 'Terrestre')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (23, 24, 'Vélo')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (25, 26, 'Voiture')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (27, 28, 'Camion')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (29, 34, 'Moto')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (30, 31, 'Side-car')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (32, 33, 'Trail')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (36, 43, 'Marin')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (37, 38, 'Planche à voile')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (39, 40, 'Paquebot')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (41, 42, 'Voilier')


Recherches dans l'arbre
Les requètes de recherche sont maintenant très simplifiées:
Recherche des "feuilles"
Une feuille est un élément final, donc l'écart entre sa borne gauche et sa borne droite est de 1:
Code SQL :
SELECT *
FROM NEW_FAMILLE
WHERE NFM_BD - NFM_BG = 1

Recherche des feuilles d'une branche
Les bornes d'une branche indiquent les éléments précédents et suivant, il nous suffit donc de lister tous les éléments dont les bornes sont strictement comprises entre BG et BD de la branche pour avoir l'intégralité des sous-éléments.
Par exemple pour la famille "terrestre" donc BG=22 et BD=35:
Code SQL :
SELECT *
FROM NEW_FAMILLE
WHERE NFM_BD - NFM_BG = 1
AND NFM_BG > 22
AND NFM_BD < 35

Recherche des noeuds
Un noeud se caractérise par le fait que BD-BG est supérieur à 1:
Code SQL :
SELECT *
FROM NEW_FAMILLE
WHERE NFM_BD - NFM_BG > 1


Insertions
L'insertion d'un élément oblige bien évidemment à faire plusieurs requètes:
La première pour décaler les bornes droites des éléments suivants ainsi que du parent, la seconde pour décaler les bornes gauches des éléments suivants et enfin la dernière pour insérer le nouvel élément.

Ainsi, si l'on veut ajouter un élément "Roller" dans la famille terrestre, il va falloir:

  1. Augmenter de 2 la valeur de toutes les bornes droites dont la valeur initiale est supérieur ou égale à 35 (ce qui inclut le parent),
  2. Augnemter de 2 la valeur des toutes les bornes gauches dont la valeur initiale est supérieure ou égale à 35 (ce qui exclut le parent),
  3. Insérer le nouvel élément.

Code SQL :
UPDATE NEW_FAMILLE SET NFM_BD = NFM_BD + 2 WHERE NFM_BD >= 35
UPDATE NEW_FAMILLE SET NFM_BG = NFM_BG + 2 WHERE NFM_BG >= 35
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (35, 36, 'Roller')


L'erreur est humaine, mais il faut un ordinateur pour provoquer une catastrophe
10/05/2007 09:58
Visiter le site internet de cet utilisateur Trouver tous les messages de cet utilisateur Citer ce message dans une réponse
CrazyCat
Administrator
*******


Messages : 130
Groupe : Administrateurs
Inscription : Feb 2007
Statut : Absent
Réputation : 0
Message : #2
RE: [Algoritmie] Parcours d'une hiérarchie

Suppression d'un noeud
La suppression d'un élément se fait avec une requète sur sa borne gauche.

Code SQL :
DELETE FROM NEW_FAMILLE
WHERE NFM_BG = 11

Mais ceci nous laisse un trou dans l'arborescence et les comptes risquent d'être faussés.
Il faut donc réordonner les éléments qui se trouvent à droite, en décrémentant leur borne gauche et leur borne droite de 2:
Code SQL :
UPDATE NEW_FAMILLE SET NFM_BG = NFM_BG - 2 WHERE NFM_BG >= 11
UPDATE NEW_FAMILLE SET NFM_BD = NFM_BD - 2 WHERE NFM_BD >= 11


On peut presque aussi simplement supprimer un noeud et tout ses contenus, il suffit de supprimer tous les éléments dont la borne gauche est supérieure ou égale à la borne gauche du noeud considéré et dont la borne droite est inférieure ou égale à la borne droite du noeud:
Code SQL :
DELETE FROM NEW_FAMILLE
WHERE  NFM_BG >= 22
AND NFM_BD <= 35

Pour renuméroter les éléments qui se trouvent à droite, il faut décrémenter les bornes gauches et droites d'une valeur simplement calculable: (BD - BG + 1), ce qui dans notre cas donne 14.
Code SQL :
UPDATE NEW_FAMILLE SET NFM_BD = NFM_BD - 14 WHERE NFM_BD >= 22
UPDATE NEW_FAMILLE SET NFM_BG = NFM_BG - 14 WHERE NFM_BG > 22


L'insertion d'un noeud complet serait aussi simple, à la différence qu'il faut bien entendu effectuer les décalages avant d'insérer les enregistrements.

Avec une base de données acceptant les procédures stockées, on peut très facilement automatiser les différentes opérations.


L'erreur est humaine, mais il faut un ordinateur pour provoquer une catastrophe
10/05/2007 12:32
Visiter le site internet de cet utilisateur Trouver tous les messages de cet utilisateur Citer ce message dans une réponse
CrazyCat
Administrator
*******


Messages : 130
Groupe : Administrateurs
Inscription : Feb 2007
Statut : Absent
Réputation : 0
Message : #3
RE: [Algoritmie] Parcours d'une hiérarchie

Voici un article fort intéressant de Patrick Haederli, qui en plus propose une classe PHP pour la gestion de de ce type de hiérarchies.


L'erreur est humaine, mais il faut un ordinateur pour provoquer une catastrophe
26/06/2007 09:45
Visiter le site internet de cet utilisateur Trouver tous les messages de cet utilisateur Citer ce message dans une réponse
Poster une réponse  Créer un sujet 

Voir une version imprimable
Envoyer ce sujet à un ami
S'abonner au sujet | Ajouter le sujet aux favoris

Aller à :