iwink/tree

PHP 的树数据结构

v1.0.1 2022-04-05 10:46 UTC

This package is auto-updated.

Last update: 2024-09-05 16:10:32 UTC


README

License Tag

此组件提供了一个可以遍历和修改的

Tree 接收一个根 Node 并包含遍历根节点中包含的节点的方法

  • visitPostOrder 首先遍历其子节点(从左到右),然后遍历自身。
  • visitInOrder 首先遍历其左子节点,然后遍历自身,最后遍历其右子节点。
  • visitPreOrder 首先遍历自身,然后遍历其子节点(从左到右)。
  • visitLevelOrder 按层级遍历。

访问者

此树实现了 访问者模式。此组件包含了一些常见的访问者。

还包括2个提供基本实现的抽象访问者

  • Visitor 实现了空的 beforeVisiting()afterVisiting() 方法。
  • ArrayVisitor 记录每次访问的结果,可以在访问者完成后通过调用 getResult(): iterable 来读取。

创建自己的访问者

要创建自己的访问者,需要让它实现 VisitorInterface 或扩展抽象的 VisitorArrayVisitor 类。

有时需要在访问者开始访问之前或访问完成后执行某些操作。在这种情况下,可以使用 beforeVisiting()afterVisiting() 方法。例如,ArrayVisitor 总是在 beforeVisiting() 上重置内部数组,以防止在多次调用上堆叠结果。

示例

构建树

<?php

use Iwink\Tree\Node\Node;
use Iwink\Tree\Tree;
use Iwink\Tree\Visitor\ValueVisitor;

$nodes = [];
foreach (range('A', 'I') as $value) {
	$nodes[$value] = new Node($value);
}

$nodes['D']->addChild($nodes['C'], $nodes['E']);
$nodes['H']->addChild($nodes['G'], $nodes['I'], $nodes['J']);
$nodes['B']->addChild($nodes['A'], $nodes['D']);
$nodes['F']->addChild($nodes['B'], $nodes['H']);

$tree = new Tree($nodes['F']);

这个树的视觉表示如下

         F
      /      \
     B        H
   /  \     / | \
  A    D   G  I  J
     /  \
   C     E

遍历树

现在我们可以遍历这个树并应用一个访问者

// See code block above

$visitor = new ValueVisitor('strtolower'); // Convert the node's value to lowercase

$tree->visitPreOrder($visitor);
var_dump(iterator_to_array($visitor->getResult())); // ['f', 'b', 'a', 'd', 'c', 'e', 'h', 'g', 'i', 'j']

$tree->visitInOrder($visitor);
var_dump(iterator_to_array($visitor->getResult())); // ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' 'j']

$tree->visitPostOrder($visitor);
var_dump(iterator_to_array($visitor->getResult())); // ['a', 'c', 'e', 'd', 'b', 'g', 'i', 'j', 'h', 'f']

$tree->visitLevelOrder($visitor);
var_dump(iterator_to_array($visitor->getResult())); // ['f', 'b', 'h', 'a', 'd', 'g', 'i', 'j', 'c', 'e']

序列化树

要将树持久化到文件或数据库记录,可以使用 TreeInterface::serialize(?callable $converter = null)。这会将树序列化为保留层次结构并可恢复的格式。如果节点值不是标量,则可能需要传递一个 $converter 到此方法,以便这些值也可以序列化。

从序列化格式构建树

如果您有一个序列化的树,可以使用 TreeInterface::fromSerialized(array $serialized, ?callable $converter = null, string $node_class = Node::class) 来恢复它。它接受一个可选的 $converter 来恢复节点值,如果这不是标量值。您还可以传递自己的 $node_class 实现来创建由不同节点组成的树。只需确保您的节点类实现了 NodeInterface 即可。