簡體   English   中英

PHP中遍歷樹的數據結構?

[英]data structure for traversal tree in PHP?

我沒有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 |
+-------------+----------------------+-----+-----+

我在考慮使用數組,但看起來很麻煩。 如果它是這樣的數組數組: array( 'name'=> "PORTABLE ELECTRONICS", 'lft' => 10, 'rgt' = 19 ) ,那么重復循環遍歷該數組會很麻煩所有數字都存在等

由於PHP有一些新的數據結構可用,我想知道這些中的任何一個是否會比使用數組帶來任何好處?

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

編輯:此類不會是存儲在數據庫表中的樹的網關。 (如果是的話,我只會對類進行查詢。)它只是某種PHP數據結構中的獨立mmpt。

編輯:好的,我再看一下這個。 我認為命名法有所混淆。 您不是在尋找PHP中的多個data structure for a transveral treedata structure for a transveral tree 您希望在PHP中使用樹作為數據結構,並且希望使用稱為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;
    }

顯然,您可以將$ 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();      
?>

PS:像你建議的那樣在嵌套數組中用PHP存儲數據將非常困難。 在上面的類中,如果刪除了數據成員,則修改樹(包括添加整個子樹等),仍然可以正確檢索lftrgt值。

如果使用數組來存儲信息,那么刪除包含父項和子項的項目將非常困難,並且更新lft和rgt valuse將非常困難。 最后,向陣列添加大集(子樹)也非常困難。

樹真的是存儲這種分層數據的理想方式。 它模仿我們的集合概念。 問題是雖然PHP很容易存儲樹,但MySQL卻沒有,所以我們需要經歷修改的預訂樹遍歷的所有困難工作,以便從PHP樹中提取信息,以便我們可以將它存儲在MySQL數據庫中。

一個帶有Node和Tree對象的簡單運行程序。 女士們,先生們,沒有任何進一步的麻煩,這里是代碼:

<?php
#Create a node class
#-----------------------------------------------------------------------------
class Node
{
    #The node properties
    public $value;
    public $leftChild;
    public $rightChild;

    #Set the properties for the node
    public function set_value($passedValue)
    {
        $this->value = $passedValue;
    }

    public function set_left_child($passedChild)
    {
        $this->leftChild = $passedChild;
    }

    public function set_right_child($passedChild)
    {
        $this->rightChild = $passedChild;
    }

    #Get the properties for the node
    public function get_value()
    {
        return $this->value;
    }

    public function get_left_child()
    {
        return $this->leftChild;
    }

    public function get_right_child()
    {
        return $this->rightChild;
    }
}





#Create a tree class with a function to transverse the node
#-----------------------------------------------------------------------------
class Tree
{
    #The node properties
    public $treeNodes = array();
    public $preorderedNodes = array();
    public $nodeArray = array();

    #Set the tree nodes from the passed array
    public function set_tree_nodes($nodeArray)
    {
        $this->nodeArray = $nodeArray;
        #Set each node with its children based on the passed array
        foreach($this->nodeArray AS $node) array_push($this->treeNodes, $this->set_node_object($node));
    }


    public function set_node_object($node)
    {
        $nodeObject = new Node();
        $nodeObject->set_value($node['value']);
        if(!empty($node['left_child'])) $nodeObject->set_left_child($this->nodeArray[$node['left_child']]);
        if(!empty($node['right_child'])) $nodeObject->set_right_child($this->nodeArray[$node['right_child']]);

        return $nodeObject;
    }

    #perfom a preorder transversal on the tree and return the tree nodes in the expected order
    public function do_preorder_transversal($node)
    {
        #If the node is empty, end the recursion
        if(empty($node)) return $this->preorderedNodes;
        #Start the transversal
        if($node == 'head' && !empty($this->treeNodes[0])) $node=$this->treeNodes[0]; 

        #Add the node to the pre-ordered node list
        array_push($this->preorderedNodes, $node);

        $leftChild = $node->get_left_child(); 
        $rightChild = $node->get_right_child(); 
        if(!empty($leftChild)) $this->do_preorder_transversal($this->set_node_object($leftChild));
        if(!empty($rightChild)) $this->do_preorder_transversal($this->set_node_object($rightChild));
    }


    #Get the preordered nodes
    public function get_preordered_nodes()
    {
        return $this->preorderedNodes;
    }
}









#-----------------------------------------------------------------------------
# Test the objects
#-----------------------------------------------------------------------------
#Call the class in an example
$sampleTree = new Tree();

$seedData = array();
#Seed data array is in the format [value, [key to left child], [key to right child]]
$seedData[0] = array('value'=>2, 'left_child'=>1, 'right_child'=>2);
$seedData[1] = array('value'=>7, 'left_child'=>3, 'right_child'=>4);
$seedData[2] = array('value'=>5, 'left_child'=>'', 'right_child'=>7);
$seedData[3] = array('value'=>2, 'left_child'=>'', 'right_child'=>'');
$seedData[4] = array('value'=>6, 'left_child'=>5, 'right_child'=>6);
$seedData[5] = array('value'=>5, 'left_child'=>'', 'right_child'=>'');
$seedData[6] = array('value'=>11, 'left_child'=>'', 'right_child'=>'');
$seedData[7] = array('value'=>9, 'left_child'=>8, 'right_child'=>'');
$seedData[8] = array('value'=>4, 'left_child'=>'', 'right_child'=>'');

$sampleTree->set_tree_nodes($seedData);
#Create the root node to start the tree transversal
$sampleTree->do_preorder_transversal('head');

#Now get the preordered nodes and print out their values
$preordered = $sampleTree->get_preordered_nodes();
foreach($preordered AS $count=>$node) echo "<BR>[".$count."] ".$node->get_value();
?>

結果如下:

[0] 2

[1] 7

[2] 2

[3] 6

[4] 5

[5] 11

[6] 5

[7] 9

[8] 4

這是我用來構建二叉樹及其在PHP中的操作的代碼:

  <?php
class Node
{
 public $data;
 public $leftChild;
 public $rightChild;

 public function __construct($data)
  {
   $this->data=$data;
   $this->leftChild=null;
   $this->rightChild=null;
  }
 public function disp_data()
  {
   echo $this->data;
  }


}//end class Node
class BinaryTree
{
 public $root;
 //public $s;
 public function __construct()
  {
   $this->root=null;
   //$this->s=file_get_contents('store');

  }
//function to display the tree
  public function display()
  {
   $this->display_tree($this->root);

  }
  public function display_tree($local_root)
  {

   if($local_root==null) 
     return;
    $this->display_tree($local_root->leftChild);
    echo $local_root->data."<br/>";
    $this->display_tree($local_root->rightChild);

  } 
// function to insert a new node
  public function insert($key)
   {
    $newnode=new Node($key);
      if($this->root==null)
        {
         $this->root=$newnode;
         return;
        }
      else
        {
         $parent=$this->root;
         $current=$this->root;
           while(true)
             {
               $parent=$current;
                 //$this->find_order($key,$current->data);
                if($key==($this->find_order($key,$current->data)))
                  {
                      $current=$current->leftChild;
                       if($current==null)
                         {
                          $parent->leftChild=$newnode;
                          return;
                         }//end if2
                  }//end if1 
                else
                  {
                      $current=$current->rightChild;
                       if($current==null)
                         {
                          $parent->rightChild=$newnode;
                          return;  
                         } //end if1                       
                  } //end else
             }//end while loop 
        }//end else

   } //end insert function

//function to search a particular Node
 public function find($key)
  {
    $current=$this->root;
     while($current->data!=$key)
          {
            if($key==$this->find_order($key,$current->data))
              {
                $current=$current->leftChild;
              }
            else
              {
                $current=$current->rightChild;
              }
            if($current==null)
              return(null);

          }
         return($current->data); 
  }// end the function to search
 public function delete1($key)
  {
    $current=$this->root;
    $parent=$this->root;

    $isLeftChild=true;
     while($current->data!=$key)
          {
           $parent=$current;
           if($key==($this->find_order($key,$current->data)))
             {
              $current=$current->leftChild;
              $isLeftChild=true;
             }   
           else
             {
              $current=$current->rightChild;
              $isLeftChild=false;   
             } 
            if($current==null)
              return(null);
          }//end while loop 

      echo "<br/><br/>Node to delete:".$current->data;
     //to delete a leaf node 
     if($current->leftChild==null&&$current->rightChild==null)
       {
           if($current==$this->root)
              $this->root=null;  
          else if($isLeftChild==true)
           {
            $parent->leftChild=null;
           }  
         else
           {
            $parent->rightChild=null;
           }
         return($current);       
       }//end if1
     //to delete a node having a leftChild 
   else if($current->rightChild==null)
       {
          if($current==$this->root)
           $this->root=$current->leftChild;
          else if($isLeftChild==true)
           {
            $parent->leftChild=$current->leftChild;
           }
          else
           {
            $parent->rightChild=$current->leftChild;
           }   
          return($current);
       }//end else if1
    //to delete a node having a rightChild
   else if($current->leftChild==null)
       {
         if($current==$this->root)
           $this->root=$current->rightChild;
         else if($isLeftChild==true)
           {
            $parent->leftChild=$current->rightChild;
           }  
         else
           {
            $parent->rightChild=$current->rightChild; 
           }  
           return($current);
       }  
   //to delete a node having both childs
    else
       {
        $successor=$this->get_successor($current);
        if($current==$this->root)
          {
            $this->root=$successor; 

          }
        else if($isLeftChild==true)
          {
           $parent->leftChild=$successor;
          }
        else
          {
           $parent->rightChild=$successor;
          }     
         $successor->leftChild=$current->leftChild;
        return($current);
       }   


  }//end the function to delete a node
//Function to find the successor node
 public function get_successor($delNode)
  {
   $succParent=$delNode;
   $successor=$delNode;
   $temp=$delNode->rightChild;
    while($temp!=null)
         {
          $succParent=$successor;
          $successor=$temp;
          $temp=$temp->leftChild;
         }
   if($successor!=$delNode->rightChild)
     {
      $succParent->leftChild=$successor->rightChild;
      $successor->rightChild=$delNode->rightChild;
     }
  return($successor);
  }
//function to find the order of two strings
 public function find_order($str1,$str2)
  {
     $str1=strtolower($str1);
     $str2=strtolower($str2);
     $i=0;
     $j=0;

     $p1=$str1[i];
     $p2=$str2[j]; 
  while(true)
   {  
       if(ord($p1)<ord($p2)||($p1==''&&$p2==''))
         {

           return($str1);
         }
      else
         {
           if(ord($p1)==ord($p2))
             {
              $p1=$str1[++$i];
              $p2=$str2[++$j];
              continue;
             }
          return($str2); 
         }
   }//end while

  } //end function find string order

 public function is_empty()
  {
    if($this->root==null)
      return(true);
    else
      return(false);
  }
}//end class BinaryTree
?>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM