news 2026/8/25 9:13:42

Ardent迭代器家族源码全解:栈与队列实现4种树遍历的完整清单

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Ardent迭代器家族源码全解:栈与队列实现4种树遍历的完整清单

Ardent迭代器家族源码全解:栈与队列实现4种树遍历的完整清单

【免费下载链接】ArdentA Collections library for PHP.项目地址: https://gitcode.com/gh_mirrors/ard/Ardent

Ardent 是一个面向 PHP 的集合(Collections)库,它的迭代器家族用队列两种基础结构,优雅地实现了二叉树的 4 种经典遍历:前序、中序、后序和层序。本文将带你快速读懂这套源码的设计思路,帮你彻底搞懂"树遍历为什么离不开栈与队列"。

一、先认识 Ardent 迭代器家族 🌳

Ardent 的核心理念是:PHP 标准库(SPL)对常用数据结构的封装并不够丰富,而数组又被过度使用。Ardent 补上了这块空白,用面向对象的方式实现了链表、栈、队列、集合、映射、二叉树等结构。

其中,二叉树的遍历能力由一个专门的接口统一约束:

  • 接口定义:src/Collection/BinaryTreeIterator.php(继承Enumerator,实现Countable

所有树遍历迭代器都实现该接口,因此它们可以像数组一样被foreach遍历,也可以用count()获取节点总数。

二、为什么栈和队列是树遍历的"最佳拍档" 🔑

树是递归结构,但非递归遍历需要借助额外结构来"记住"访问路径:

数据结构访问顺序适合场景
栈(LIFO 后进先出)先压入的先被处理的是"最近"的节点深度优先:前序、中序、后序
队列(FIFO 先进先出)先入队的先被处理广度优先:层序(按层)遍历

一句话总结:深度优先靠栈"回头",广度优先靠队列"排队"

三、4 种遍历迭代器完整清单 📋

遍历方式迭代器类依赖结构源码位置
前序(根→左→右)PreOrderIteratorsrc/Collection/PreOrderIterator.php
中序(左→根→右)InOrderIteratorsrc/Collection/InOrderIterator.php
后序(左→右→根)PostOrderIteratorsrc/Collection/PostOrderIterator.php
层序(逐层)LevelOrderIterator队列src/Collection/LevelOrderIterator.php

下面逐个拆解它们的关键实现。

1. 前序遍历:栈模拟"先访问根"

PreOrderIterator的思路非常直观:

  • rewind():新建一个LinkedStack,把根节点压栈(见src/Collection/PreOrderIterator.php第 42~47 行)
  • next():弹出栈顶节点,先压右子、再压左子(利用栈的后进先出,保证左子先被访问)

这个"右左颠倒压栈"的 trick 是前序遍历非递归实现的标准写法。

2. 中序遍历:栈保存"左链"

InOrderIteratorsrc/Collection/InOrderIterator.php)是四种实现中最简洁的:

  • rewind():调用私有方法pushLeft(),把从根节点开始的所有左子节点一路压栈(第 110~114 行)
  • current()直接返回栈顶节点的值
  • next():弹出栈顶,如果它有右子树,就把右子树的左链再压栈

栈在这里扮演的是"回溯路径"的角色——随时能回到未完成的祖先节点。

3. 后序遍历:最复杂的栈实现

PostOrderIteratorsrc/Collection/PostOrderIterator.php)的难点在于"根最后访问"。源码用一组私有小方法拆解状态机:

  • next_valueNotNull():把当前节点的右子入栈,然后沿左子继续(第 115~121 行)
  • next_right():判断右子是否已处理,决定是否"回退"到栈中继续
  • next_set():把当前节点确定为输出值并移动 key

阅读建议:先弄清"栈中存的是父节点链",再看每个分支如何修改value指针,状态机就清晰了。

4. 层序遍历:队列逐层出队

LevelOrderIteratorsrc/Collection/LevelOrderIterator.php)是唯一的"广度优先"实现:

  • rewind():初始化队列为[根节点](第 43~47 行)
  • next()array_shift()取出队首节点,把它的左子、右子依次入队(第 81~94 行)
  • 队列空时遍历结束

虽然这里内部用了数组模拟队列(而非LinkedQueue),但思想与队列完全一致:先进先出保证同层节点按顺序访问。

四、底层支撑:栈与队列是怎么实现的 💪

4 个遍历迭代器站在两个基础集合之上:

  • LinkedStacksrc/Collection/LinkedStack.php):
    • 基于链表节点Pair实现,push()新节点直接指向旧top(第 45~48 行)
    • pop()返回top->first并前进指针,last()可在不弹出时偷看栈顶——树遍历迭代器正是靠last()拿到"当前节点"
  • LinkedQueuesrc/Collection/LinkedQueue.php):
    • 维护headtail双指针,enqueue()尾插(第 41~51 行)、dequeue()头删(第 57~64 行),两端操作都是 O(1)
    • first()支持不取出查看队首

两者都是 O(1) 的入/出操作,这正是它们适合作为遍历引擎的原因。相关接口定义见src/Collection/Stack.phpsrc/Collection/Queue.php

五、动手验证:测试用例在哪里跑 🧪

每个迭代器都有对应的单元测试,直接看"输入树 → 期望输出序列"最容易建立直觉:

  • test/Collection/BinarySearchTree/InOrderIteratorTest.php
  • test/Collection/BinarySearchTree/PreOrderIteratorTest.php
  • test/Collection/BinarySearchTree/PostOrderIteratorTest.php
  • test/Collection/BinarySearchTree/LevelOrderIteratorTest.php
  • 公共基类:test/Collection/BinarySearchTree/BinaryTreeIteratorTest.php

克隆仓库后(仓库地址:https://gitcode.com/gh_mirrors/ard/Ardent),用phpunit.xml配置即可运行全部测试,观察四种遍历在 BST 上输出的有序/有序变体序列。

六、小结:一张清单带走核心要点 ✨

  1. 前序、中序、后序 = 栈:深度优先遍历靠栈保存回溯路径;
  2. 层序 = 队列:广度优先靠队列保证逐层顺序;
  3. 四种迭代器统一实现BinaryTreeIterator接口,支持foreachcount()
  4. 栈/队列本身基于Pair链表节点,入出操作均为 O(1)。

读懂这 4 个文件(约 400 行),你就掌握了非递归树遍历的全部套路——这也是 Ardent 迭代器家族最值得入门的一处源码。

【免费下载链接】ArdentA Collections library for PHP.项目地址: https://gitcode.com/gh_mirrors/ard/Ardent

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/25 9:12:19

网络安全校招岗位解析与职业规划指南

1. 网络安全校招现状与核心痛点2023年网络安全行业校招出现明显的两极分化现象:头部企业为渗透测试岗位开出50万年薪的天价offer,而部分传统企业的安全运维岗却仍停留在10-15万的薪资区间。这种巨大的薪资差异背后,反映的是企业对不同安全岗位…

作者头像 李华
网站建设 2026/8/25 9:09:03

rosbag2 从零跑通 ROS2 录制回放:安装、录制与回放实用指南

rosbag2 从零跑通 ROS2 录制回放:安装、录制与回放实用指南 【免费下载链接】rosbag2 项目地址: https://gitcode.com/gh_mirrors/ro/rosbag2 rosbag2 是 ROS2 的官方录制回放工具:它把系统中带时间戳的消息写入磁盘,之后随时把 bag …

作者头像 李华
网站建设 2026/8/25 9:08:56

JavaScript核心概念与高频面试题解析

1. JavaScript 基础知识点全景解析作为一名从业十年的全栈开发者,我见过太多初学者在JavaScript学习路上踩坑。今天这份总结将系统梳理JS核心概念,结合高频面试题和实际开发中的痛点,帮你构建完整的知识框架。不同于教科书式的罗列&#xff0…

作者头像 李华
网站建设 2026/8/25 9:07:31

小厂前端实习面试全攻略:高频考点与实战技巧

1. 真实小厂前端实习面试全记录去年冬天我投递了十几家中小型互联网公司的前端实习岗位,最终拿到了3个offer。这段经历让我深刻认识到:小厂面试和大厂完全是两种不同的游戏规则。没有复杂的算法题和系统设计,但每个问题都直指实际工作场景。今…

作者头像 李华
网站建设 2026/8/25 9:05:42

2026软件测试面试全攻略:理论与实战解析

1. 2026软件测试面试全攻略:从八股文到实战技巧最近帮团队面试了几十位测试工程师候选人,发现即使是工作3-5年的应聘者,面对基础理论问题时也常常支支吾吾。这让我意识到,系统化的面试准备对测试工程师至关重要。这份指南不仅包含…

作者头像 李华