Aller au menu - Aller au contenu

[Plan du site] Vous êtes ici --- > Le Site du Zér0 > Les tutoriels > Non-Officiels > Site Web > PHP > Base de données > Lecture du tutoriel

La Représentation Intervallaire

Avatar
Auteur : Talus
Créé : le 28/06/2007 14:40:17
Modifié : le 17/07/2007 16:13:27
Noter et commenter ce tutoriel
Imprimer ce tutoriel
Vous vous apprêtez à lire un tutoriel rédigé par un membre de ce site. Malgré tout le soin que ce membre a pu apporter au tutoriel, nous ne pouvons pas garantir que les informations contenues sur cette page sont exactes à 100%. Merci de garder cela en tête lorsque vous lirez cette page ;o)
Une notion bien étrange que voilà...

Pour mieux expliquer, prenons (par exemple) des forums, ayant plusieurs "niveaux" (comprenez sous-forums). Pour accéder aux "enfants" et aux "parents" d'un forum, vous pensez sûrement (et, je pense, vous les utiliserez) les héritage (présence d'une colonne "parent_id", méthode également connue sous le nom de Représentation Classique) par auto-jointures, c'est à dire en renseignant récursivement la clause WHERE à l'aide de sous requêtes.
Mais, ceci peut très vite devenir lourd... et peu pratique, surtout à partir d'un certain niveau (et qui, au grand dam de tous, est vite atteint).

Notez que, tout au long du tutoriel, pour la plupart des exemples, j'utiliserais l'exemple de Forums ;)


Dans ce tuto, nous allons donc voir comment éviter cette lourdeur en employant une "ruse" mise au point par les développeurs : la Représentation Intervallaire !
Accrochez vous, on y va !
Sommaire du chapitre :

La Théorie

Une (petite) présentation de tout le "schmilblik"



Avant d'attaquer la bête, nous avons, tout d'abord, besoin de la définir. Tout d'abord, qu'est-ce la Repr...

C'est vrai ça, c'est quoi la Rapré... Représentation Invert... cette chose ?


La Représentation Intervallaire ! Je la voyais arriver à des kilomètres à la ronde celle là !

Je commence par un point optionnel (ce sera plus facile à expliquer). Cette technique peut permettre de situer un élément dans une hiérarchie. Pour donner une image de cette notion de hiérarchie, prenons l'exemple d'un immeuble, couplé à un système de forums (vous allez très vite comprendre). Vous savez, un immeuble est constitué d'étages...
Disons que la catégorie d'un système de forums est le rez-de-chaussée de cet immeuble, et, les étages, les sous forums (qui sont chacun des sous forums de l'étage précédent). Voilà ce qu'est la notion de hiérarchie : si je suis au quatrième étage (non, non, je ne vais pas sauter :D ), ça veut dire que je suis.. au quatrième niveau, ou à la quatrième hiérarchie. Il peut, bien entendu, y avoir plusieurs sous forums ayant le même niveau, comme, toujours à l'image d'un immeuble, il peut y avoir plusieurs appartements à chaque étage.

Ensuite, un point essentiel à retenir dans la Représentation Intervallaire (je vois pas ce qu'il y a de compliqué à retenir là dedans, ce n'est quand même pas de L'acide acétyli... Acide acytéli... bref, un certain médicament :p ), les notions de borne gauche, borne droite.

Pour illustrer cette notion, voici un schéma fait par mes soins (mes capacités en graphisme étant très limitées, vous m'excuserez de la qualité de celui-ci), qui, je dois vous l'avouer, reprends un peu la même idée que le schéma de Frédéric Brouard (le mien étant simplifié, et (surtout) plus adapté à notre cas de développeur en herbe), qui d'ailleurs présente de très bons tutos sur SQL.

Image utilisateur
Merci à Shadow_f pour le schéma.


Comme vous pouvez le voir, chaque borne de chaque élément se voit attribuer un nombre. Ce nombre permet de déterminer la position de l'élément dans l'ensemble. Notez également que le nombre de la borne gauche est toujours inférieur au nombre de la borne droite. Notez bien ce point, il est très important (je fais une liste de rappel à la fin de cette première sous-partie) !

A propos de points importants, en voilà un autre à noter : si la différence entre sa borne droite et sa borne gauche (et non pas l'inverse !) est égale à 1, on désigne alors l'élément étant une feuille (non, non, on ne parle pas de joint Image utilisateur). Sinon, ce sera un noeud, et cette même différence sera égale au double du nombre d'enfants, auquel on ajoute 1.

Je pense que vous constaterez qu'au lieu de mettre des noms aux éléments sur mon schéma, j'ai juste indiqué les niveaux de chaque élément, pour vous montrer la tête que ça peut avoir.

Euh... C'est bien beau tout ça, mais quels sont les points essentiels de la Représentation Intervallaire ?


J'y viens, et vous posez la question pile au bon moment. Je vous ai fait une petite liste de trucs à retenir....



Il vous faut surtout retenir ces trois derniers points, ce sont les plus importants !


Passons maintenant à la préparation pour pouvoir pratiquer, dans la 2nde partie de ce tutorial (majoritairement des requêtes SQL pour servir à titre d'exemples) ; Je montrerai également pourquoi il est difficile (et coûteux) d'utiliser les "auto-jointures" (c'est à dire d'utiliser avec abus la clause WHERE et les sous-requêtes) pour accéder aux noeuds parents et aux feuilles... Et que c'est même presque impossible pour nous en ce moment. A moins d'avoir des idées tordues... :lol:

Pourquoi préférer la RI à l'héritage récursif ? Les tables SQL d'exemples.



Dans cette sous-partie, je considère que vous savez manipuler SELECT et ses clauses WHERE et ORDER BY, et (éventuellement) comprendre les requêtes d'insertion. Sinon, vous avez la porte, le big tutorial de M@téo21, "Faire un dynamique avec PHP - Base de Données", le big tutorial de Shepard, "Pour aller plus loin..." à dispositions.


L'héritage récursif ? Ourf, c'est lourd... et infaisable (pour des zér0s comme nous) :D



Voici la table type que nous allons utiliser pour illustrer la faiblesse ( :p ) de l'héritage récursif :

Code : SQL
 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
CREATE TABLE tuto_herit (
        forum_id mediumint(8) NOT NULL AUTO_INCREMENT,
        forum_parent_id mediumint(8) DEFAULT NULL,
        forum_name varchar(50) NOT NULL,
        PRIMARY KEY  (forum_id),
        KEY forum_parent_id (forum_parent_id)
);

INSERT INTO tuto_herit (forum_id, forum_parent_id, forum_name) 
        VALUES 
                (1, NULL, '1'),
                (2, 1, '1.1'),
                (3, 2, '1.1.1'),
                (4, 3, '1.1.1.1'),
                (5, 4, '1.1.1.1.1'),
                (6, 5, '1.1.1.1.1.1'),
                (7, 6, '1.1.1.1.1.1.1'),
                (8, 6, '1.1.1.1.1.1.2'),
                (9, 6, '1.1.1.1.1.1.3'),
                (10, 4, '1.1.1.1.1.2'),
                (11, 4, '1.1.1.1.1.3'),
                (12, 4, '1.1.1.1.2'),
                (13, 4, '1.1.1.1.3'),
                (14, 2, '1.1.2'),
                (15, 1, '1.2'),
                (16, 1, '1.3'),
                (17, 1, '1.4'),
                (18, 11, '1.4.1'),
                (19, 11, '1.4.2'),
                
                (20, NULL, '2')/*,[...]*/;


Notez que j'ai délibérément choisi de nommer les éléments en fonction de leur parent, pour pouvoir les distinguer. Ainsi, X.Y.Z veut dire que l'élément correspondant appartient à un parent X, qui a un fils Y, ... etc.


A partir d'un des sous-forums (on va dire celui ayant l'id numéro 7, le plus profond :diable: ), comment faire, à l'aide des jointures, pour accéder à la catégorie 1, en affichant tous les forums parents au sous-forum sélectionné ? Je vous laisse 5 minutes pour essayer de faire cette requête... Et bien entendu, en ayant qu'un seul forum par ligne (pas tous, sinon ce serait trop facile, surtout si on connaît la profondeur du sous-forum :p )

...

...

Vous y arrivez pas ? Pour tout vous avouer, moi non plus :D . Ici, on peut facilement avoir tous les forums parents sur la même ligne à l'aide de quelques jointures (en utilisant l'héritage de la colonne forum_parent_id), or ce n'était pas ce qui était demandé : on voulait un forum par lignes. Certes, les jointures, c'est pratique, mais à la longue... C'est vite pesant et peu pratique.

N.d.A :: Pour ce problème, je pense qu'il faut soit utiliser la récursivité d'une fonction pour trouver ce qu'on cherche, mais ça reste consommateur de ressource si l'Arbre est trop profond (dans notre cas même ce peut être considéré comme trop profond), ou alors, toujours dans la récursivité, une série de sous-requêtes, ce qui n'est également pas trop terrible.


La Représentation Intervallaire ? Yeay !



Reprenons la première Table... En l'adaptant un quelque peu pour pouvoir la rendre utilisable par la Représentation Intervallaire... Hop, là voilà prête à l'emploi (toujours avec les insertions, converties qui plus est :magicien: ) !

Code : SQL
 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
CREATE TABLE tuto_ri (
        forum_id mediumint(8) NOT NULL AUTO_INCREMENT,
        forum_level mediumint(8) NOT NULL DEFAULT 0,
        forum_gauche mediumint(8) NOT NULL,
        forum_droite mediumint(8) NOT NULL,
        forum_name varchar(30) NOT NULL,
        PRIMARY KEY  (forum_id),
        KEY forum_gauche (forum_gauche),
        KEY forum_droite (forum_droite)
);

INSERT INTO tuto_ri (forum_id, forum_level, forum_gauche, forum_droite, forum_name) 
        VALUES 
                (1, 0, 1, 38, '1'),
                (2, 1, 2, 27, '1.1'),
                (3, 2, 3, 24, '1.1.1'),
                (4, 3, 4, 23, '1.1.1.1'),
                (5, 4, 5, 18, '1.1.1.1.1'),
                (6, 5, 6, 13, '1.1.1.1.1.1'),
                (7, 6, 7, 8, '1.1.1.1.1.1.1'),
                (8, 7, 9, 10, '1.1.1.1.1.1.2'),
                (9, 8, 11, 12, '1.1.1.1.1.1.3'),
                (10, 5, 14, 15, '1.1.1.1.1.2'),
                (11, 5, 16, 17, '1.1.1.1.1.3'),
                (12, 4, 19, 20, '1.1.1.1.2'),
                (13, 4, 21, 22, '1.1.1.1.3'),
                (14, 2, 25, 26, '1.1.2'),
                (15, 1, 28, 29, '1.2'),
                (16, 1, 30, 31, '1.3'),
                (17, 1, 32, 37, '1.4'),
                (18, 2, 33, 34, '1.4.1'),
                (19, 2, 35, 36, '1.4.2'),
                
                (20, 0, 39, 40, '2')/*,[...]*/;


La note concernant les noms des (sous-)forums reste toujours valable dans ce même cas.

Allez, même exercice que tout à l'heure ! Vous avez... 10 minutes pour le faire : rechercher l'id, le nom, et la hiérarchie des noeuds parents de la feuille ayant l'id "7", en les triant du parent le plus proche au parent plus lointain !

...

...

...

...

...

...

Ah, c'est vrai, j'avais oublié le petit indice : utiliser les bornes des feuilles. Si vous n'aviez pas deviné (nan, surtout pas, pas la fenêtre :waw: !), ce n'est pas grave, voici ma solution, et pour tenter de me faire pardonner ( :ange: ), je l'ai commentée pour vous la faire mieux comprendre).

Secret (cliquez pour afficher)

Code : SQL
1
2
3
4
5
SELECT forum_id, forum_name
        FROM tuto_ri
        WHERE forum_gauche < 7 
                AND forum_droite > 8
        ORDER BY forum_level DESC;



Image utilisateur
On retrouve donc ce qu'on recherchait.



On cherche à récupérer l'ID, le nom, et la hiérarchisation des noeuds parents, ce qu'on fait en sélectionnant les champs "forum_id", "forum_name", et "forum_level".
Ensuite, dans la clause WHERE, on applique ce qu'on a pu observer sur mon (beau :p ) schéma : La borne gauche d'un des (sous-)forums est toujours plus grande que celle des noeuds parents. On sélectionne donc tous les noeuds ayant une borne gauche plus petite que (dans notre cas) 7. On applique la même chose à la borne droite, sauf que cette fois ci, la borne droite de la feuille est toujours plus petite que celle des noeuds parents.

On a donc les noeuds que l'on désire... Mais ce n'est pas fini, il y avait un petit piège : on souhaite avoir les noeuds... Du plus proche au plus lointain par rapport à la feuille. Il suffisant juste d'ajouter une petite clause ORDER BY, en indiquant le nom de la colonne qui sert à trier (forum_level), et par ordre décroissant. Je vous l'avais bien dit que la notion de hiérarchisation pouvait s'avérer utile par moments... En voilà la preuve même !

Notez que si je vous avais demandé, dans la liste des forums ressortie, de ressortir également le forum dans lequel on est, à la place des opérateurs < et > utiliser <= et >=. En effet, la borne gauche du forum est bien plus petite ou égale à la borne de notre forum, et la borne droite est bien plus petite ou égale ;)



Image utilisateur
Ici, on cherche aussi à inclure le forum courant dans le résultat.


Bon, je vous pense prêt pour la pratique : à l'assauuuuuut :pirate: !

La Pratique

Ici, nous allons voir les différentes techniques et opérations chirurgicales liées à la Représentation Intervallaire : modifier le statut d'un élément (transformer un noeud en une feuille, et vice-versa), ajouter des feuilles à un noeud, compter le nombre d'éléments dans un noeud, pouvoir mettre à jour les indices aux bornes en fonction du nombre d'éléments (en fonction que ce soit une feuille ou un noeud), ...

Cette Partie du tuto agira donc en tant que plusieurs séries de "Mini-TPs", qui demandent par moments de la réflexion, et par moments des astuces... que je développerai ici.

Stats sur les différents noeuds


Dans cette sous-partie, nous allons voir comment compter le nombre d'éléments d'un noeud, le nombre de feuilles d'un noeud, le nombre de noeuds dans un même noeud, ... Bref, on va compter :p

Compter le nombre d'éléments d'un noeud


Pour compter le nombre d'éléments d'un noeud, ça va être relativement (très) simple, et (très) vite expédié. Vous vous souvenez, à la fin de la première partie de ce tuto, on a vu comment récupérer tous les parents (et leur caractéristiques) d'une feuille / d'un noeud, en incluant ou non l'élément, non ? Eh bien ici, ça va plus ou moins être le même topo.

Ha ! Laisse moi deviner : Au lieu d'inclure l'élément dans la sélection, on va déjà devoir utiliser les signes strictement supérieurs / inférieurs, non ?


Bingo ! De plus, vous aurez besoin, comme je l'ai dit, non pas de sélectionner les parents de l'élément, mais ses enfants ! Donc, au lieu de rechercher tous les éléments qui ont une borne gauche inférieure à celle de l'élément recherché, et une borne droite supérieure à celle de l'élément, on va faire l'inverse !
Je vous file la solution dans quelques minutes, le temps pour vous de chercher (et moi d'aller piquer un petit somme :ninja: ). Ah, j'oubliais pour quel forum on va faire cette opération : cette fois-ci, on va chercher le nombre d'enfants pour le forum ayant l'ID numéro... 3 !

Petit Indice : Utilisez la fonction d'agrégat COUNT(*) (Pour les fonctions d'agrégat, voyez le tutorial de Dentuk sur le sujet)

...

...

Hmm ? vous avez (déjà) fini ? Voici donc la correction :) .
Secret (cliquez pour afficher)

Code : SQL
1
2
3
4
SELECT COUNT(*)
        FROM tuto_ri
        WHERE forum_gauche > 3 
                AND forum_droite < 24;


Vous avez vu, ce n'était pas si sorcier, il suffisait juste donc d'inverser les signes pour les deux bornes pour obtenir les enfants et non pas les parents du noeud, et d'utiliser, comme je vous l'ai dit, la fonction d'agrégat COUNT(*).


Image utilisateur
On trouve donc 10 éléments fils au noeud '1.1.1'.

Image utilisateur
Dans le sens inverse, on retrouve 2 éléments parents au noeud '1.1.1'.



Vous verrez par la suite (bon, tout de suite après pour tout vous avouer :D ) que le nombre d'éléments parents est forcément celui des noeuds parents (c'est de la pure logique ;) )


Compter le nombre de feuilles / de noeuds d'un noeud


Mais... Mais... N'est-ce pas la même chose que ce qu'on a fait à l'instant même ?

Pas tout à fait. Ici, on ne chercher pas à compter tous les enfants (ou les parents) d'un noeud, mais seulement les feuilles (ou les noeuds) enfants (ou les parents) d'un noeud. Donc, on va à peu près procéder de la même manière qu'auparavant, mais, tachez juste de vous rappeler d'un des points à retenir de la Représentation Intervallaire. Vous y êtes ? Non ? Bon bah cherchez le nombre de noeuds enfants pour le même forum que le précédent :p (Et ça va me permettre d'aller chercher un café pour finir de me réveiller :ninja: )

...

...

...

...

Que vous ayez fini ou non, voici la correction !
Secret (cliquez pour afficher)

Code : SQL
1
2
3
4
5
SELECT COUNT(*)
        FROM tuto_ri
        WHERE forum_gauche > 3 
                AND forum_droite < 24 
                AND (forum_droite - forum_gauche) = 1;



Image utilisateur
On trouve 7 feuilles filles pour le "Forum 1.1.1"



Ce TP était également plutôt facile ; il suffisait de se souvenir que pour toutes les feuilles d'un arbre, la différence entre les deux bornes est toujours égale à 1. De même, pour compter le nombre de noeuds fils, vous pouvez, je pense, aisément le deviner, il faut chercher non pas les fils ayant une différence entre leurs bornes égal à 1, mais supérieur à 1.


Image utilisateur
On trouve 3 noeuds fils pour le noeud "1.1.1"

Image utilisateur
On trouve 0 feuilles parentes pour le noeud "1.1.1"

Image utilisateur
On trouve 2 noeuds parents pour le noeud "1.1.1"


Pour le troisième résultat, je suppose que vous vous en doutiez : un enfant ne peut avoir de feuilles parentes. Ou alors c'est qu'il y a un problème au niveau des bornes :-°


De même, vous vous doutez que si vous mettez un signe supérieur (resp. inférieur) ou égal à 1 pour la différence, ça équivaut à la même chose que tout à l'heure... Si ce n'est de pomper des ressources inutilement :D


Dernière remarque : Si vous additionnez les deux premiers résultats, vous pourrez retrouver le résultat qu'on a vu plus haut, soit tous les éléments fils du noeud "Forum 1.1.1"... Même remarque pour les éléments parents ;) .


Mettre à jour un élément



Ici, on va voir comment mettre à jour un élément : Mettre ses bornes à jour (ajout / suppression d'éléments), mise à jour qui peut entraîner la transformation d'une feuille en un noeud (et vice et versa :p ), ... Bref, on va s'amuser à mettre à jour notre arbre :D

Ajout / Suppression d'éléments (transformation d'une feuille en un noeud "simple", d'un noeud "simple" en une feuille)


Déjà, vous devez connaître comment insérer / supprimer des lignes d'une base de donnée, à l'aide des requêtes INSERT et DELETE.... Vous y êtes ? On va insérer une nouvelle ligne par la droite à la feuille de niveau 4, 1.[...].3 (ID N°13). Pour cela, puisque nous connaissons déjà la borne gauche, la borne droite, et le niveau de la feuille, on évite une requête. Enfin, c'est à vous de voir si vous voulez (ou non) ajouter une requête SELECT, ça dépend des cas.

De plus, on aura également besoin de faire 2 Updates : changer les bornes gauches et droites de tous les éléments à partir duquel on souhaite y insérer la nouvelle feuille. Donc, à chacune des bornes, on va incrémenter tout d'abord la borne droite de 2, puis la borne gauche de... 2 également, et le tout en 2 requêtes. Pourquoi deux ? Pour ne pas nous embêter à pondre un truc trop complexe, et pour une raison que je préciserais dans le corrigé, plus bas. Après tout, pourquoi faire complexe quand on peut faire simple ?
Et enfin, on insère la nouvelle feuille.. par la droite. Pourquoi par la droite ? Parce que c'est plus pratique... :p
Mais après, libre à vous de suivre le conseil que je vous donne (qui est également celui de Mr Brouard) ^^

Ici, on cherche donc à insérer notre nouvelle feuille par la droite : je vous laisse un peu de temps (pour percuter) et essayer de pondre les requêtes.

Euh... Mais attends, je comprends pas, pourquoi appelle-tu ceci un noeud "simple" :euh: ?


Ah, c'est vrai, je n'ai pas détaillé. J'appelle ici noeud "simple" le fait que ce noeud n'ait qu'une feuille, et le fait que l'on insère que des feuilles.... et pas des noeuds. Je détaillerai dans le prochain Mini-TP comment procéder dans ce cas (pour retirer un noeud d'un arbre aussi ^^ ). Bref, allez-y, la correction arrive dans quelques instants ;) .

...

...

...

Voici la correction tant désirée :)
Secret (cliquez pour afficher)

Code : SQL
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
UPDATE tuto_ri
        SET forum_droite = forum_droite + 2
        WHERE forum_droite >= 22;
        
UPDATE tuto_ri 
        SET forum_gauche = forum_gauche + 2
        WHERE forum_gauche >= 22;

INSERT INTO tuto_ri (forum_level, forum_gauche, forum_droite, forum_name) 
        VALUES
                (5, 22, 23, '1.1.1.1.3.1');



Image utilisateur
Insertion d'une feuille dans un noeud / une feuille



Vous ayant tout expliqué avant, c'était juste une application de ce que j'ai dis plus haut :p

Lorsqu'on sélectionne les données, on trouve la feuille insérée à la bonne place (ici, je n'ai sélectionné que les colonnes "forum_gauche", "forum_droite", et "forum_name", pour éviter d'avoir une largeur trop grande pour mon screen) :


Image utilisateur
OK, tout est correct !


Vous pouvez ainsi transformer une "simple" feuille en un noeud... "simple".


Je pense que vous devinez aussi comment supprimer une feuille :

Code : SQL
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
DELETE 
        FROM tuto_ri
        WHERE forum_gauche = 22;

UPDATE tuto_ri
        SET forum_gauche = forum_gauche - 2
        WHERE forum_gauche >= 22;

UPDATE tuto_ri
        SET forum_droite = forum_droite - 2
        WHERE forum_droite >= 22;


Le topo est à peu près le même que pour l'insertion, sauf que cette fois-ci, on commence d'abord par la suppression, puis par la mise à jour de la borne gauche, et enfin par la mise à jour de la borne droite ; j'expliquerai pourquoi, lors de l'insertion, on commence toujours par la mise à jour de la borne droite, puis de la borne gauche, puis l'insertion, et dans le sens inverse lors de la suppression (enfin, on change l'insertion par la suppression, je pense que ça, vous l'avez déjà percuté :p ), plus en bas pour résumer ce TP.


Image utilisateur
Suppression d'une feuille dans un noeud / Retransformation d'un noeud "simple" en une feuille.

Image utilisateur
On retourne à l'état initial


Alors ? Pourquoi recommandes-tu d'exécuter ces actions dans cet ordre précis ?


C'est juste pour ne pas avoir d'erreurs trop bêtes, si vous avez mis des contraintes d'unicité sur vos deux bornes. Ainsi, lors de l'insertion, on décale d'abord toutes les bornes à partir de laquelle on veut insérer notre feuille, pour pouvoir ensuite décaler les bornes gauches des feuilles suivantes sans que la borne gauche ne soit jamais égale à la borne droite (phew). Ensuite seulement on insère la feuille à la borne désirée. Pour la suppression, c'est à peu près le même topo, mais dans le sens inverse.

Pour la suppression, vous n'êtes pas obligé de devoir tout redécaler, mais suivez mon conseil, et faîtes-le, histoire d'avoir un arbre plus propre et ne pas avoir "trop" de trous et pas mal d'emmerdes au fur et à mesure des différentes opérations.


Maintenant, si vous êtes toujours là, on va aborder la même chose... Mais avec des noeuds, c'est à dire l'insertion et la suppression d'un noeud dans un arbre :soleil: !

Insertion / Suppression d'un sous-arbre (noeud) dans un arbre


Ici, je pense pas avoir besoin de détailler... Vous avez juste besoin de connaître les bornes de l'arbre à insérer, le nombre d'élément qu'il contient, et ça devrait faire l'affaire, si on emploie la même méthode que tout à l'heure ;)

Voici l'arbre que l'on va chercher à insérer :

Image utilisateur
Merci à Shadow_f pour le schéma.


On va donc rattacher cet arbre à la feuille "2", c'est à dire celle étant comprise entre les bornes... 39 et 40, donc, en ayant cet arbre, sachant qu'il y a 9 éléments, la différence entre les deux bornes de la catégorie 2 va donc être égale à (je sors ma calculette :D ) : 2*9+1, soit 19. Donc, la borne gauche de la catégorie reste égale à 39, mais la borne droite sera égale à... 19+39... 58 ! De même, on aura besoin d'incrémenter toutes les bornes droite du double du nombre d'éléments dans le noeud à insérer, soit... 9*2.. 18 !

Je vous laisse cogiter un peu (n'oubliez pas de décaler les bornes de l'arbre à insérer... Vous verrez que c'est plutôt facile ;) )...

...

...

C'est bon, vous y êtes ? Voilà la correction !
Secret (cliquez pour afficher)

Code : SQL
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
UPDATE tuto_ri
        SET forum_droite = forum_droite + 18
        WHERE forum_droite >= 40;

UPDATE tuto_ri
        SET forum_gauche = forum_gauche + 18
        WHERE forum_gauche >= 40;

INSERT INTO tuto_ri (forum_level, forum_gauche, forum_droite, forum_name) 
        VALUES 
                (1, 40, 57, '2.1'),
                (2, 41, 46, '2.1.1'),
                (2, 47, 48, '2.1.2'),
                (2, 49, 50, '2.1.3'),
                (2, 51, 56, '2.1.4'),
                (3, 42, 43, '2.1.1.1'),
                (3, 44, 45, '2.1.1.2'),
                (3, 52, 53, '2.1.4.1'),
                (4, 54, 55, '2.1.4.2');



Image utilisateur
Insertion d'un arbre (noeud) dans un noeud : transformation d'une feuille en un noeud.



Bon, c'est vrai, fallait faire des maths : ajouter 39 (borne gauche de l'élément "récepteur", c'est à dire la catégorie 2) à toutes les bornes de ce noeud (et à ses éléments fils), pour le rendre "compatible" avec notre arbre récepteur. Ensuite, c'était une insertion des plus banales : Il faut décaler les bornes de tous les éléments de notre arbre de.. petit calcul... 18, pour le rendre compatible avec notre arbre. Soit, le double du nombre d'éléments à rajouter (9 éléments dans notre cas). Pour les niveaux, il "suffisait" juste de sélectionner les niveaux de l'arbre, et leur additionner le niveau du noeud auquel on veut fixer le nouvel arbre. Or, comme notre noeud "récepteur" a un niveau égal à 0... dans notre cas, ça n'a aucun effet (si ce n'est consommer des ressources) :p

Notez qu'ici, puisque la "catégorie 2" qu'en plus d'être simple feuille, elle est le dernier élément de notre arbre : la seconde requête UPDATE ne sert donc (dans notre cas) à rien, mais je l'ai mise pour vous signaler son existence. Rien de plus, rien de moins ;) .


Image utilisateur
Et voilà le travail :)


Voici la suppression (vous pouviez la deviner, quand même :p ) :
Code : SQL
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
DELETE 
        FROM tuto_ri
        WHERE forum_gauche >= 40 
                AND forum_droite <= 57;

UPDATE tuto_ri
        SET forum_gauche = forum_gauche - 18
        WHERE forum_gauche >= 40;
                
UPDATE tuto_ri
        SET forum_droite = forum_droite - 18
        WHERE forum_droite >= 57;


C'était tout simplement un mélange entre l'application de la suppression d'une feuille et l'insertion d'un arbre. Comme pour la suppression d'une feuille, les mises à niveau des bornes de l'arbre dans lequel on a supprimé notre noeud, elles ne sont pas obligatoire, mais restent un plus non négligeable pour avoir un Arbre propre et pourvoir éviter les trous trop gros dans l'arbre au fur et à mesure des opérations :p

Dans notre cas, comme pour l'insertion, la mise à jour des bornes gauche de tous les éléments n'était pas nécessaire, car notre catégorie 2 se retransforme en simple feuille, tout en étant la dernière de notre arbre.


Image utilisateur
Suppression d'un sous-arbre (noeud à plusieurs éléments fils) dans un noeud : transformation d'un noeud en une feuille.

Image utilisateur
On retourne à notre configuration initiale


Comme pour l'insertion, pour connaître le nombre à soustraire aux deux bornes, il "suffisait" de connaitre le nombre d'éléments à supprimer, et à le doubler... Un peu de maths n'a jamais tué personne :p !

C'est "déjà" la fin de ce tutorial :'( .
Maintenant, vous savez gérer un bel outil nommé la "Représentation Intervallaire", qui vous permet de vous débrouiller avec aisance pour gérer un super système de catégorie (allant jusqu'à une profondeur très-très-très-(...)très grande (voir infinie)) de ce-que-vous-voulez (l'exemple le plus probant étant celui des forums, ou bien, par exemple, comme sur le SdZ, des tutos par exemple... :p )

En complétant avec des Procédures Stockées (Voyez le tuto de Draeli sur ce sujet), et autres fonctions, vous pourrez probablement (et sûrement :D ) faire des merveilles pour gérer vos arbres ;)
Auteur : Talus
Noter et commenter ce tutoriel
Imprimer ce tutoriel

Nombre de connectés 632 Zér0s connectés | Requêtes SQL 7 requêtes | Temps de génération de la page 0.0421s (0.0148s)

Changer de design - Revue de presse - En savoir plus - Plan du site
Nous contacter - Mentions légales - Publicité
Politique d'accessibilité - Fil RSS - XHTML 1.0 - CSS 2.0

Y'a plus rien à lire, faut remonter maintenant !