![](/img/trans.png)
[英]What kind of data structure can be used in php for preorder traversal of tree?
[英]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有一些新的數據結構可用,我想知道這些中的任何一個是否會比使用數組帶來任何好處?
編輯:此類不會是存儲在數據庫表中的樹的網關。 (如果是的話,我只會對類進行查詢。)它只是某種PHP數據結構中的獨立mmpt。
編輯:好的,我再看一下這個。 我認為命名法有所混淆。 您不是在尋找PHP中的多個data structure for a transveral tree
的data 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方法。 這使用修改的預訂樹遍歷運行樹,並顯示每個名稱的lft和rgt數量,使您能夠將數據作為嵌套集存儲在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值以及樹可視化。
<?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存儲數據將非常困難。 在上面的類中,如果刪除了數據成員,則修改樹(包括添加整個子樹等),仍然可以正確檢索lft
和rgt
值。
如果使用數組來存儲信息,那么刪除包含父項和子項的項目將非常困難,並且更新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.