8

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
  • LinkedList
  • SplStack
  • SplQueue
  • SplHeap
  • SplMaxHeap
  • SplMinHeap
  • SplPriorityQueue
  • SplFixedArray
  • SplObjectStorage

編集:このクラスは、データベーステーブルに格納されているツリーへのゲートウェイにはなりません。(もしそうなら、私はクラスのクエリを持っているでしょう。)それはある種のPHPデータ構造のスタンドアロンmmptです。

4

3 に答える 3

8

編集:わかりました、私はこれをもう少し調べました。命名法に混乱があったと思います。data structure for a transveral treeあなたはPHPでを探していません。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では、単純なツリーを使用できます。問題は、MySQLであるフラットデータベースにツリーを格納するのは簡単ではないということです。1つのオプションは、PHPを取得し、そこから隣接リストを取得することです。これは基本的に、各アイテムとその親のリストです。このやり方にはいくつかの欠点があります。

もう1つの方法は、階層データから作成できるネストされたセットを記述する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値、およびツリーの視覚化を出力します。

コードパッドでコードを実行できます

<?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の値を更新するのは非常に困難です。最後に、大きなセット(サブツリー)を配列に追加することも非常に困難です。

ツリーは、この種の階層データを格納するための理想的な方法です。それは私たちの集合の概念を模倣しています。問題は、PHPはツリーを簡単に保存しますが、MySQLは簡単に保存できないため、PHPツリーから情報を抽出してMySQLデータベースに保存できるようにするには、変更されたプレオーダーツリートラバーサルのすべての困難な作業を実行する必要があります。

于 2010-08-06T07:35:47.027 に答える
1

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

于 2014-09-26T05:24:57.830 に答える
0

これは、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
?>
于 2010-12-05T10:13:11.693 に答える