首页 > 解决方案 > PHP中的嵌套数据集结构

问题描述

我正在尝试在 PHP中实现嵌套数据集结构的面向对象版本(结构的另一种描述)。我已经创建了一个节点实现:

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);

标签: phpoopphp-7recurrence

解决方案


您不应该定义父对象或对它的引用,因为您可能最终会陷入引用循环,这在代码中但在设计中并不是一件坏事,并且最终可能会使您的代码在出现问题时无法理解。

至于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 而是使用 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;
    }
}

而且因为我 return $this,我可以链接所有内容,或者嵌套 addNode 调用,例如

$country = new Node();
$state = new Node();
$city = new Node();
$country->addNode($state->addNode($city));

推荐阅读