PHP中遍历树的数据结构?

use*_*841 7 php mptt modified-preorder-tree-t data-structures

我没有CS或数据结构的背景知识.我想创建一个PHP类,它存储一个修改过的预订序横向树,用于操作和与数据库同步.

基本上我需要存储数据,如:

+-------------+----------------------+-----+-----+
| category_id | name                 | lft | rgt |
+-------------+----------------------+-----+-----+
|           1 | ELECTRONICS          |   1 |  20 |
|           2 | TELEVISIONS          |   2 |   9 |
|           3 | TUBE                 |   3 |   4 |
|           4 | LCD                  |   5 |   6 |
|           5 | PLASMA               |   7 |   8 |
|           6 | PORTABLE ELECTRONICS |  10 |  19 |
|           7 | MP3 PLAYERS          |  11 |  14 |
|           8 | FLASH                |  12 |  13 |
|           9 | CD PLAYERS           |  15 |  16 |
|          10 | 2 WAY RADIOS         |  17 |  18 |
+-------------+----------------------+-----+-----+
Run Code Online (Sandbox Code Playgroud)

我在考虑使用数组,但看起来很麻烦.如果它是这样的数组数组:array( 'name'=> "PORTABLE ELECTRONICS", 'lft' => 10, 'rgt' = 19 )那么重复循环遍历该数组会很麻烦,以确保所有数字都存在,等等.

由于PHP有一些新的数据结构可用,我想知道这些中的任何一个是否会比使用数组带来任何好处?

  • SplDoubly
  • 链表
  • SplStack
  • SplQueue
  • SplHeap
  • SplMaxHeap
  • SplMinHeap
  • SplPriorityQueue
  • SplFixedArray
  • SplObjectStorage

编辑:此类不会是存储在数据库表中的树的网关.(如果是的话,我只会对类进行查询.)它只是某种PHP数据结构中的独立mmpt.

Pet*_*tai 7

编辑:好的,我再看一下这个.我认为命名法有所混淆.你不是在寻找data structure for a transveral treePHP.您希望在PHP中使用树作为数据结构,并且您希望使用名为the的方法从该树恢复数据modified preorder tree traversal algorithm.

引用:

When working with a tree, we work from left to right, one layer at a time, descending to each node's children before assigning a right-hand number and moving on to the right. This approach is called the modified preorder tree traversal algorithm.


这是关于在PHP与MySQL中存储分层数据.在PHP中,我们可以使用一个简单的树.问题是在平面数据库中存储树并不容易.一种选择是从中获取PHP和检索和邻接列表.这基本上是每个项目及其父项的列表.这种做事方式有一些缺点.

另一种方法是从PHP树中提取信息,该信息描述可以从分层数据中生成的嵌套集.要从PHP树中获取此信息,我们需要使用修改后的预订树遍历算法.这是一种在树上运行的方法,以便从中提取某些信息.

无论我们使用邻接列表模型还是修改的预序树遍历来检索信息,我们都使用完全相同的PHP树.不同之处在于我们如何从树中检索信息以及我们如何在MySQL中存储信息.有关如何从MySQL提取信息的代码已经在您引用的页面上.要在PHP和MySQL之间同步数据,您只需使用该页面上描述的MySQL技术和PHP树类.

为此,我在PHP中创建了一个存储树的类.它使用节点.每个节点都可以被认为是完整树的根,因为从每个节点可以访问完整的子树.将节点与树分开更容易,并且它可以减少开销.

该类的重要部分是showAdjacency方法.这使用修改的预订树遍历运行树,并显示每个名称的lftrgt数量,使您能够将数据作为嵌套集存储在MySQL中.

您还可以显示树,以便可以将其可视化.此类中缺少删除方法.实现它时,必须将已删除节点的子节点传递给节点的父节点.也许我以后会这样做.

我将在帖子的底部包含整个类,但这里是如何检索修改的预订树遍历的数据:

      // The modified preorder tree traversal.
    private function showAdjacency($root, $spaces)
    {
          // Print the data first
        if ($root)
        {
              // On the way down the tree, we get lft.
            $left = ++$spaces;                
            foreach( $root->next as $child)
            {                    
                if ($child)
                {
                    $spaces = $this->showAdjacency($child, $spaces);                      
                }
            }
        }
          // On the way back up, we get rgt.
        $right = ++$spaces;
        echo "$left - $right - $root->data <br/>";                
        return $spaces;
    }
Run Code Online (Sandbox Code Playgroud)

显然,您可以将$ root-> data,$ rgt和$ lft存储在用于与数据库同步的数组中.

这是整个班级.课程结束后,我使用您链接到的页面中的示例数据创建树,然后输出lft和rgt值以及树形图.

您可以在Codepad上运行代码

<?php  
  // Class defintions and methods:
  // It's easier to use separate nodes. Each node still points to an entire and complete subtree.
class Node
{
    public $data;
    public $next = array();
}

  // A first try at creating a tree with any number of branches from its nodes
  // by Peter Ajtai - feel free to use and modify
class Tree
{
    // The root
    private $root;
    public function __construct()
    {
        $this->root = NULL;
    }

      // The public wrapper. 
      // This is needed because we must start the recursive functions
      // at the root, and we do not want to give public access to root.
      // I am not familiar w overloading in PHP, maybe __set should be used for this
    public function insertPub($data, $parent)
    {
        $root =& $this->root;
        $this->insert($root, $data, $parent);
    }

    private function insert(&$root, $data, $parent)
    {

          // Create the root of the entire tree if no parent is passed in        
        if (!$root && !$parent)
        {
            $root = new Node;
            $temp =& $root;
            $temp->data = $data;
            // Create space for next insertion
            $temp->next[] = NULL;                     
        } else if ($root->data == $parent)
        {

              // Add data as a child if we're at the parent, and we're done.
              // Find the empty node to insert at
            foreach($root->next as &$child)
            {
                  // Insert at the first (and only) NULL
                if (!$child)
                {
                    $child = new Node;
                    $temp =& $child;
                    $temp->data = $data;                        
                    // Create space for next insertion
                    $temp->next[] = NULL;
                }
            }
              // Create space for the next insertion
            $root->next[] = NULL;
        } else
        {
              // Keep searching for the parent as default behavior.
            foreach($root->next as $child)
            {
                if ($child)
                {
                    $this->insert($child, $data, $parent);
                }
            }
        }
    }
      // Public wrapper for the display function.
    public function showAdjPub()
    {
        echo "The neighbors:<br/><br/>";
        $root =& $this->root;
        $this->showAdjacency($root, 0);
        echo "<br/>";
    }

      // The display function.
    private function showAdjacency($root, $spaces)
    {
          // Print the data first
        if ($root)
        {
            $left = ++$spaces;                
            foreach( $root->next as $child)
            {                    
                if ($child)
                {
                    $spaces = $this->showAdjacency($child, $spaces);                      
                }
            }
        }
        $right = ++$spaces;
        echo "$left - $right - $root->data <br/>";                
        return $spaces;
    }
      // Public wrapper for the display function.
    public function showAllPub()
    {
        echo "The tree:<br/><br/>";
        $root =& $this->root;
        $this->showAll($root, 0);
        echo "<br/>";
    }

      // The display function.
    private function showAll($root, $spaces)
    {
          // Print the data first
        if ($root)
        {
            for ($i=0; $i < $spaces; ++$i)
                echo "---> ";
            echo "$root->data <br/>";
            ++$spaces;
            foreach( $root->next as $child)
            {                    
                if ($child)
                {
                    $this->showAll($child, $spaces);
                }
            }
        }
    }        
}

  // Create a new instance of the tree
$myTree = new Tree;

  // Insert the data into the tree.    
  // The following data would be retrieved using MySQL
$name = 'Electronics'; $parent = NULL;
$myTree->insertPub($name, $parent);
$name = 'Televisions'; $parent = 'Electronics';
$myTree->insertPub($name, $parent);
$name = 'Tube'; $parent = 'Televisions';
$myTree->insertPub($name, $parent);    
$name = 'Lcd'; $parent = 'Televisions';
$myTree->insertPub($name, $parent); 
$name = 'Plasma'; $parent = 'Televisions';
$myTree->insertPub($name, $parent);    
$name = 'Portable Electronics'; $parent = 'Electronics';
$myTree->insertPub($name, $parent);    
$name = 'MP3 Players'; $parent = 'Portable Electronics';
$myTree->insertPub($name, $parent);    
$name = 'Flash'; $parent = 'MP3 Players';
$myTree->insertPub($name, $parent);    
$name = 'CD Players'; $parent = 'Portable Electronics';
$myTree->insertPub($name, $parent);    
$name = '2 Way Radios'; $parent = 'Portable Electronics';
$myTree->insertPub($name, $parent);    

  // Display adjacency
$myTree->showAdjPub();

  // Show hierarchy    
$myTree->showAllPub();      
?>
Run Code Online (Sandbox Code Playgroud)

PS:像你建议的那样在嵌套数组中用PHP存储数据将非常困难.在上面的类中,如果删除了数据成员,则修改树(包括添加整个子树等),仍然可以正确检索lftrgt值.

如果使用数组来存储信息,那么删除包含父项和子项的项目将非常困难,并且更新lft和rgt valuse将非常困难.最后,向阵列添加大集(子树)也非常困难.

树真的是存储这种分层数据的理想方式.它模仿我们的集合概念.问题是虽然PHP很容易存储树,但MySQL却没有,所以我们需要经历修改的预订树遍历的所有困难工作,以便从PHP树中提取信息,以便我们可以将它存储在MySQL数据库中.