2010-11-13 14 views
6

Ho esaminato l'elenco di adiacenza e il modello di set annidato per trovare la soluzione di albero ottimale.Elenco di adiacenza rispetto al modello di serie nidificato

Fino ad ora ho pensato che uno dei principali vantaggi di Nested Set Model era che potevo usare una query SQL e del codice per ottenere un albero completo. Ma è complicato aggiornare/inserire i nodi e l'intero albero può facilmente essere corrotto.

Poi mi sono imbattuto in questi due messaggi:

Recursive categories with a single query?

http://www.sitepoint.com/forums/showthread.php?t=570360

Il seguente codice mi permette di utilizzare adiacenza List con una query SQL. Mi sembra che Adjacency List sia più facile da aggiornare e meno probabile che corrompa l'intero albero.

Cosa ne pensi di questo codice?

generare un array multidimensionale per riflettere la struttura ad albero

$nodeList = array(); 
    $tree = array(); 

    $query = mysql_query("SELECT id, title, page_parent FROM categories ORDER BY page_parent"); 
    while($row = mysql_fetch_assoc($query)){ 
     $nodeList[$row['id']] = array_merge($row, array('children' => array())); 
    } 
    mysql_free_result($query); 

    foreach($query AS $row){ 
     $nodeList[$row['id']] = array_merge($row, array('children' => array())); 
    } 

    foreach ($nodeList as $nodeId => &$node) { 
     if (!$node['page_parent'] || !array_key_exists($node['page_parent'], $nodeList)) { 
      $tree[] = &$node; 
     } else { 
      $nodeList[$node['page_parent']]['children'][] = &$node; 
     } 
    } 

    unset($node); 
    unset($nodeList); 

Preparare una lista non ordinata con nodi nidificati

function printMenu ($arrTreeToTraverse, $ext = '.html', $breadcrumb = '') { 

// Pre loop stuff 
echo "<ul class=\"sf-menu\">\r\n"; 

foreach ($arrTreeToTraverse as $objItem) { 

    // Stuff relevant to the item, before looping over its children 
    if ($objItem['page_parent'] != 0) { 
     $breadcrumb .= '/'.$objItem['uri']; 
    } 
    else 
    { 
     $breadcrumb .= $objItem['uri']; 
    } 

    if ($objItem['uri'] == 'index') { 
     echo '<li><a href="/">'.$objItem['title'].'</a>'; 
    } else { 
     echo '<li><a href="'$_SERVER['SERVER_NAME'].'/'.$breadcrumb.$ext.'">'.$objItem['title'].'</a>'; 
    } 

    if ($objItem['children']) { 
    echo "\r\n"; 

     // Call the function again on the children 
     printMenu($objItem['children'], $ext, $breadcrumb); 
    }// if 

    // Extend breadcrumb if it is a child or 
    // reset breadcrumb if first level of tree 
    $parent = explode('/', $breadcrumb); 
    if ($objItem['page_parent'] != 0) { 
     $breadcrumb = $parent[0]; 
    } else { 
     $breadcrumb = ''; 
    } 

    echo "</li>\r\n"; 
}// foreach 

// Post loop stuff 
echo "</ul>\r\n"; 

}// function 

printMenu($navigation, '.html'); 
+0

Sembra ok tranne la riga 'foreach ($ query AS $) che non è necessaria e genererà un errore. – Fanis

risposta

7

Il codice sembra essere abbastanza ok e dato un numero ragionevole di righe (milioni di righe non lo sono) non ti colpirà troppo duramente.

Ma credo che tu abbia fatto la domanda sbagliata:

annidata imposta entrano in gioco quando è necessario gerarchie traslazione e che sarebbe troppo costoso per andare a prendere l'intera tabella per trovare il genitore del genitore di un determinato nodo. Con gli elenchi di adiacenza avresti bisogno di più query per raggiungere questo obiettivo o lasciare che PHP esegua il lavoro con cicli annidati (il che significa che O (n^2) è il caso peggiore).

In entrambi i casi, gli insiemi nidificati generalmente offrono prestazioni migliori quando si trovano gli antenati come obiettivo (ad esempio, trovare un prodotto in una gerarchia di categorie nidificate).

Vedi questo articolo: Managing Hierarchical Data in MySQL. Vi darà un buon punto di partenza su come implementare le varie domande/aggiornamenti/inserimenti/cancellazioni.

Problemi correlati