因为自定义树结构未实现iterable接口,缺少iterator()方法;需手动实现迭代器,如用栈模拟中序遍历的深度优先状态机,并避免在单个类中混用多种遍历逻辑。

为什么不能直接用 for-each 遍历自定义树结构
Java 的 for-each 要求对象实现 Iterable 接口,而标准集合(如 ArrayList)已内置迭代逻辑;但像二叉树、图这类结构没有默认遍历顺序,for-each 会直接报错 java.lang.ClassCastException: TreeNode cannot be cast to java.lang.Iterable。这不是语法问题,是缺少 iterator() 方法的契约支持。
实现深度优先迭代器的关键三步
以二叉树中序遍历为例,必须把“递归展开过程”转为“栈驱动的迭代状态机”:
- 构造时用
Stack<treenode>></treenode>预加载最左路径,避免递归调用栈溢出 -
hasNext()只判断栈是否为空,不预计算下一个节点 -
next()弹出栈顶,立即压入其右子树的最左路径(保证下一次next()返回正确顺序)
示例片段:
class InOrderIterator<t> implements Iterator<t> {
private final Stack<treenode>> stack = new Stack();
InOrderIterator(TreeNode<t> root) {
pushAllLeft(root);
}
private void pushAllLeft(TreeNode<t> node) {
while (node != null) {
stack.push(node);
node = node.left;
}
}
public boolean hasNext() {
return !stack.isEmpty();
}
public T next() {
TreeNode<t> node = stack.pop();
pushAllLeft(node.right); // 关键:右子树的最左路径要立刻补上
return node.data;
}
}</t></t></t></treenode></t></t>
多个遍历方式共存时的命名与复用陷阱
如果同时提供前序、后序、层序迭代器,别用 TreeIterator 这种模糊名——容易让调用方误以为是通用接口。应明确标注语义:
-
PreOrderIterator、PostOrderIterator、BFSIterator - 所有具体迭代器类都实现同一
Iterator<t></t>接口,但内部状态管理完全不同 - 聚合类(如
BinaryTree)通过不同工厂方法返回对应实例:tree.preOrderIterator()、tree.bfsIterator()
切忌在同一个迭代器类里用 flag 控制遍历方式——这违反单一职责,且 hasNext() 和 next() 的状态逻辑会互相污染。
Python 中 __iter__ 的常见误写
Python 用户常犯的错误是让 __iter__ 返回自身,却没重置内部计数器:
- 错误写法:
def __iter__(self): return self→ 第二次遍历时直接从上次中断处继续,导致漏元素或异常 - 正确写法:
def __iter__(self): return InOrderIterator(self.root),每次新建迭代器实例 - 若坚持返回自身,必须在
__iter__里重置状态:self.stack = [...],否则不可重复遍历
这个细节在测试时容易被忽略——单次遍历正常,循环多次就出问题。
深度优先迭代器最难的不是写逻辑,而是把“递归思维”彻底翻译成“栈+状态变量”的显式控制流;一旦栈操作和状态更新不同步,next() 就会跳过节点或无限循环。










