Méthode efficace pour détecter la circularité ?

Méthode efficace pour détecter la circularité ? - Algo - Programmation

Marsh Posté le 09-05-2004 à 18:09:13    

Exposé de la situation :
Une base de données pour représenter un arbre, 0 comme PARENT indique la racine, un autre nombre indique que l'élément possède un autre élément parent :

Code :
  1. ID | PARENT | DATA
  2. 1  |      0 | texte1
  3. 2  |      1 | texte2
  4. 3  |      2 | texte3


 
Ce qui donne l'arbre suivant :

Code :
  1. texte 1
  2. |-texte2
  3.   |-texte3


 
Le problème :
Supposons que je modifie le PARENT de 1 de la manière suivante :

Code :
  1. ID | PARENT | DATA
  2. 1  |      3 | texte1
  3. 2  |      1 | texte2
  4. 3  |      2 | texte3


 
Voila qui me fait perdre ma racine et par conséquent l'ensemble de ma structure logique en créant une boucle.
 
La question :
Quelle méthode efficace existe-il pour détecter la circularité et empêcher que celà puisse se produire lors d'un UPDATE ? Existe-il une meilleure solution de représenter un arbre ?
 
 
Note : c'est pour un code en PHP, mais en fin de compte peu importe le langage.


Message édité par Requin le 09-05-2004 à 19:21:31
Reply

Marsh Posté le 09-05-2004 à 18:09:13   

Reply

Marsh Posté le 09-05-2004 à 19:03:05    

faut faire un trigger déclenché lors des update (et des insert aussi probablement), qui contiendra le code PL/SQL permettant de lister la liste des ID fils, et si le parent est dedans, de renvoyer une erreur ...
 
pas évident à première vue :D

Reply

Marsh Posté le 09-05-2004 à 19:30:21    

Et plus amont ne pas laisser les utilisateurs tenter d'insérer un père dans la liste des fils (pas trop clair mais on se comprend ^^)

Reply

Marsh Posté le 09-05-2004 à 19:30:53    

J'ai eu une idée... en fait je vais probablement créer une fonction récursive en PHP.
 
La fonction parcourt l'arbre depuis le futur parent d'un élément, en remontant de parent en parent jusqu'à la racine (PARENT = 0, est la condition d'arrêt), si je retombe sur mon élément de départ c'est qu'il y a  circularité et donc erreur.
 
J'ignore si il existe une méthode plus efficace qui nécessiterait moins de traitement... toutefois vue mon application la charge induite par ce traitement me semble acceptable.

Reply

Marsh Posté le 09-05-2004 à 19:45:21    

de manière générale, il existe 2 grandes techniques pour détecter les cycles dans un graphe.
 
1) avec un set, on parcourt le graphe et on met les noeud dans un set au fur et à mesure de l'avancement, si le noeud est déjà dans le set, il y a un cycle. (concome de la mémoire)
 
2) le lièvre et la tortue : on fait partir un lièvre qui passe les noeuds 2 par 2, et une tortue qui parcourt les noeuds 1 par 1, s'ils se retrouvent sur le même noeud, c'est que le lièvre a fait le tour et a rattrapé la tortue, s'il tappe le bout, c'est qu'il y avait un bout. évidement, cet algo nécessite plus d'un tour de cycle de parcourt, mais ne consome pas de mémoire.


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 09-05-2004 à 22:48:10    

nraynaud a écrit :

de manière générale, il existe 2 grandes techniques pour détecter les cycles dans un graphe.
 
1) avec un set, on parcourt le graphe et on met les noeud dans un set au fur et à mesure de l'avancement, si le noeud est déjà dans le set, il y a un cycle. (concome de la mémoire)
 
2) le lièvre et la tortue : on fait partir un lièvre qui passe les noeuds 2 par 2, et une tortue qui parcourt les noeuds 1 par 1, s'ils se retrouvent sur le même noeud, c'est que le lièvre a fait le tour et a rattrapé la tortue, s'il tappe le bout, c'est qu'il y avait un bout. évidement, cet algo nécessite plus d'un tour de cycle de parcourt, mais ne consome pas de mémoire.


 
excellent le second je connaissais pas :) complexité ?

Reply

Marsh Posté le 09-05-2004 à 22:55:52    

black_lord a écrit :

excellent le second je connaissais pas :) complexité ?

sur un hypodrôme, la tortue se fait rattraper à la fin de son premier tour, soit 2 tours pour le lièvre.


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 09-05-2004 à 23:52:02    

le premier je connaissais, pas le second...


---------------
Jubi Photos : Flickr - 500px
Reply

Marsh Posté le 09-05-2004 à 23:58:08    

Question con: si c'est une DB, pourquoi ne pas mettre le parent à NULL quand c'est la racine? Ton update serait nettement simplifié...

Reply

Marsh Posté le 10-05-2004 à 00:11:53    

Jubijub a écrit :

le premier je connaissais, pas le second...

ça a été un devoir de smalltalk quand j'étais en début de deuxième année d'IUP (implémenter les 2 algos, ce qui se fait en 5 min).
 
Depuis, je me prends régulièrement des cuites avec le prof de l'époque ...


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 10-05-2004 à 00:11:53   

Reply

Marsh Posté le 10-05-2004 à 07:50:15    

gizmo -> Car je n'aime pas le néant... je préfère définir mon intervalle de travail dans les nombres entiers positifs et interdire NULL ;)
 
Sinon voici la fonction dans sa première mouture :  

Code :
  1. function cat_checkparent($id, $parent) {
  2.      
  3.       global $db;
  4.      
  5.       if ( intval($id) == intval($parent) )
  6.       {
  7.          return false;
  8.       }
  9.       elseif ( intval($parent) == 0 )
  10.       {
  11.          return true;
  12.       }
  13.       else
  14.       {
  15.          $sql = "SELECT id,parent FROM categories WHERE id=".intval($parent);
  16.          $result = $db->sql_query($sql);
  17.          $row    = $db->sql_fetchrow($result);
  18.          // recursive call
  19.          return cat_checkparent($id, $row['parent']);
  20.       }
  21.    }


Message édité par Requin le 10-05-2004 à 07:59:26
Reply

Marsh Posté le 10-05-2004 à 09:46:18    

Ouais, enfin, de toute façon, j'atais un peu fatigué, avec 0 ca merche aussi.
 
Il suffit de faire un update table set col=value where id=blabla and col!=0. Ainsi tu évites de modifier la racine.

Reply

Marsh Posté le 10-05-2004 à 09:48:15    

oui mais il faut pouvoir modifier la racine ... mais sans créer de cycle ;)

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed