代码之家  ›  专栏  ›  技术社区  ›  Mike Doe Backs

PHP中的嵌套数据集结构

  •  0
  • Mike Doe Backs  · 技术社区  · 7 年前

    我正在尝试实现一个面向对象的 nested dataset structure 在PHP中 another description of the structure )我已经创建了一个节点实现:

    class Node
    {
        private $parent;
        private $nodes = [];
        private $level = 1;
        private $left = 1;
        private $right = 2;
    
        /**
         * @return self|null
         */
        public function getParent()
        {
            return $this->parent;
        }
    
        private function setParent(self $parent = null)
        {
            $this->parent = $parent;
        }
    
        public function getLevel(): int
        {
            return $this->level;
        }
    
        private function setLevel(int $level)
        {
            $this->level = $level;
        }
    
        public function getLeft(): int
        {
            return $this->left;
        }
    
        private function setLeft(int $left)
        {
            $this->left = $left;
        }
    
        public function getRight(): int
        {
            return $this->right;
        }
    
        private function setRight(int $right)
        {
            $this->right = $right;
        }
    
        /**
         * @return static[]
         */
        public function getNodes(): array
        {
            return $this->nodes;
        }
    
        public function addNode(Node $new)
        {
            $new->setLevel($this->getLevel() + 1);
            $this->nodes[] = $new;
    
            // @todo
        }
    }
    

    然而 我需要帮助实施 这个 addNode 方法,该方法应向当前节点添加一个新节点并更新整个树,尤其是新添加的节点、父节点、子节点等。

    为了使一切更简单,我创建了一个简单的测试用例,它将检查所有内容是否都正确实现:

    $country = new Node();
    $state = new Node();
    $city = new Node();
    $country->addNode($state);
    $state->addNode($city);
    
    assert($country->getLeft() === 1);
    assert($country->getRight() === 6);
    assert($country->getLevel() === 1);
    
    assert($state->getLeft() === 2);
    assert($state->getRight() === 5);
    assert($state->getLevel() === 2);
    
    assert($city->getLeft() === 3);
    assert($city->getRight() === 4);
    assert($city->getLevel() === 3);
    
    2 回复  |  直到 7 年前
        1
  •  0
  •   DarkMukke    7 年前

    您不应该定义父对象,也不应该定义对它的引用,因为您可能最终进入引用循环,这在代码中不是一件坏事,但在设计中却可能导致代码在出错时无法理解。

    至于 addNode 功能,你似乎走对了,

    public function addNode(Node $new)
    {
        //no need for getters and setters from inside the class
        $new->level = $this->level + 1;
        $this->nodes[] = $new;
        return $this;
    }
    

    我不知道你想干什么 left right 不过。但我想它是最上层的家长是所有的路左边,最底层的孩子是所有的路右边。在这种情况下,我只是将它与级别区分开来。

    我也不会使用private和use protected,我主要是在这里完成的,这样我就可以一路向前走,而不需要getter和setter来制作代码压缩程序,但是可以按照您的感觉来做:

    class Node
    {
    
        /**
         * @var static
         */
        protected $parent;
        /**
         * @var static[] 
         */
        protected $nodes = [];
        /**
         * @var int 
         */
        protected $level = 1;
        /**
         * @var int 
         */
        protected $left = 0;
        /**
         * @var int 
         */
        protected $right = 0;
    
    
        public function addNode(Node $new)
        {
            $new->level = $this->level + 1;
            $new->parent = $this;
            $new->left = $new->level - 1;
            if (empty($this->nodes)) {
                $this->right = 1;
            }
            $curr = $this;
            while (null !== $curr->parent) {
                //walking up to the current parent and telling it there is a new level added
                $curr->parent->right++;
                //setting the current level 1 up
                $curr = $curr->parent;
            }
    
            $this->nodes[] = $new;
            return $this;
        }
    }
    

    因为我回来了 $this ,我可以链接所有内容,或者像这样嵌套addnode调用

    $country = new Node();
    $state = new Node();
    $city = new Node();
    $country->addNode($state->addNode($city));
    
        2
  •  0
  •   Mike Doe Backs    7 年前

    休息了一天,喝了一杯咖啡,终于把这件事办好了。这并不像看起来那么简单,因为在添加新节点时必须重写整个树:

    public function addChild(Node $new): void
    {
        $this->nodes[] = $new;
        $new->setParent($this);
        $new->setLevel($this->getLevel() + 1);
        $new->setLeft($this->getLeft() + 1);
        $new->setRight($this->getLeft() + 2);
    
        $rootNode = $this;
        while (!empty($rootNode->getParent())) {
            $rootNode = $this->getParent();
        }
    
        $rootNode->setLeft(1);
        $this->updateTree($rootNode);
    }
    
    private function updateTree(Node $node): void
    {
        $startIndex = $node->getLeft();
        foreach ($node->getChildren() as $child) {
            $child->setLeft(++$startIndex);
            $child->setRight(++$startIndex);
    
            if (count($child->getChildren())) {
                $this->updateTree($child);
                $startIndex = $this->getLastChild($child)->getRight();
            }
        }
    
        $node->setRight($this->getLastChild($node)->getRight() + 1);
    }
    
    private function getLastChild(Node $node): Node
    {
        return $node->getChildren()[count($node->getChildren()) - 1];
    }
    

    这个类不久将在Github上发布。