iwink / tree
PHP 的树数据结构
v1.0.1
2022-04-05 10:46 UTC
Requires
- php: ^7.4|^8.0
Requires (Dev)
- phpunit/phpunit: ^9.5
- squizlabs/php_codesniffer: ^3.6
README
此组件提供了一个可以遍历和修改的 树。
树
Tree
接收一个根 Node
并包含遍历根节点中包含的节点的方法
visitPostOrder
首先遍历其子节点(从左到右),然后遍历自身。visitInOrder
首先遍历其左子节点,然后遍历自身,最后遍历其右子节点。visitPreOrder
首先遍历自身,然后遍历其子节点(从左到右)。visitLevelOrder
按层级遍历。
访问者
此树实现了 访问者模式。此组件包含了一些常见的访问者。
ValueVisitor
返回一个包含每个节点值的数组。SerializerVisitor
返回树的序列化表示。
还包括2个提供基本实现的抽象访问者
Visitor
实现了空的beforeVisiting()
和afterVisiting()
方法。ArrayVisitor
记录每次访问的结果,可以在访问者完成后通过调用getResult(): iterable
来读取。
创建自己的访问者
要创建自己的访问者,需要让它实现 VisitorInterface
或扩展抽象的 Visitor
或 ArrayVisitor
类。
有时需要在访问者开始访问之前或访问完成后执行某些操作。在这种情况下,可以使用 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
即可。