迭代协议不直接实现图遍历算法,而是为dfs/bfs等算法提供安全、解耦、懒加载的封装接口,支持按需产出节点、链式组合、访问控制与上下文感知。

迭代协议本身不直接“实现”图遍历算法,但它为安全、可控、解耦地遍历图结构提供了设计范式。真正执行遍历的是 DFS 或 BFS 这类算法逻辑,而迭代协议(如 Python 的 __iter__/__next__,或 C++/Java 中的 Iterator 接口)负责把遍历过程封装成按需产出节点的序列——就像拉取数据流,而不是一次性加载全图。
为什么需要迭代协议来处理复杂图遍历
直接暴露图的内部存储(比如邻接表数组或邻接矩阵)会导致:外部代码依赖具体实现、难以统一访问不同图类型(稀疏/稠密、有向/无向)、无法插入访问控制或日志逻辑。迭代协议把“怎么存”和“怎么读”分开,让遍历行为可组合、可复用、可中断。
- 支持懒加载:对超大图或动态图(如网络拓扑实时更新),每次只生成下一个待访问节点,不预建完整访问序列
- 便于组合操作:可链式调用
.filter()、.take(10)、.map(transform)等,无需改写核心遍历逻辑 - 天然适配 for 循环和生成器表达式,语义清晰,降低使用门槛
如何基于迭代协议构建可扩展的图遍历器
关键不是重写 DFS/BFS,而是把它们“包装”成迭代器。以 BFS 为例:
- 状态封装:迭代器对象持有
queue(待访问队列)、visited(已访问集合)、graph(图引用)三个核心状态 - 初始化:构造时传入起始节点
start,将它加入队列并标记为已访问 -
__next__实现:出队一个节点 → 记录为当前结果 → 将其未访问邻接点入队并标记 → 返回该节点;若队列为空则抛出StopIteration
这样,for node in BFSIterator(graph, 'A'): 就能逐个获取 BFS 序列,且中途可 break 或 return,无需管理栈/队列生命周期。
应对复杂场景的协议增强技巧
真实图遍历常含约束条件(如权限过滤、权重阈值、路径长度限制),这些不应侵入基础遍历逻辑,而应通过迭代协议的分层设计注入:
-
装饰器式迭代器:写一个
FilteredIterator(it, predicate),只对底层迭代器产出的节点做条件判断,满足才 yield -
上下文感知:在
__next__中传入当前深度、父节点、累计路径等上下文,供 predicate 动态决策(例如:“跳过深度 > 5 的节点”或“仅返回带 label='user' 的顶点”) -
双向迭代支持:对支持反向边的图,提供
reverse_bfs()迭代器,复用同一套协议接口,仅改变邻接关系遍历方向
实际编码中的关键细节
避免常见陷阱才能让协议真正可靠:
- 迭代器必须是**独立状态**:多次遍历同一图需创建新迭代器实例,不能共享
visited集合,否则第二次调用会“跳过”之前访问过的节点 - 图结构变更需显式处理:若遍历中图被修改(如增删边),迭代器应抛出
RuntimeError或自动失效,不可静默返回错误结果 - 资源清理:若图底层涉及文件句柄或网络连接,迭代器应在耗尽或被垃圾回收时释放资源(Python 中用
__del__或上下文管理器)
本质上,迭代协议是图遍历的“外壳”与“接口”,它不替代算法,但让算法更健壮、更易集成、更能适应现实世界的复杂性。











