平衡二叉树中序遍历下一个元素获取及有序集合ADT迭代器实现疑问
嘿,这个问题我当初做数据结构作业的时候也踩过坑!递归遍历虽然写起来爽,但确实没法直接用来实现迭代器——毕竟递归是一次性跑完整个遍历流程,没法中途“暂停”返回单个元素。咱们来一步步拆解解决这个问题~
核心思路:用栈模拟递归调用栈
递归遍历的本质是系统帮你维护了一个调用栈,记录着需要回溯的父节点。那我们手动实现一个栈,就能复刻这个逻辑,从而控制每次只返回序列中的下一个元素,完美解决回溯问题。
以二叉搜索树的中序遍历迭代器为例(这是有序集合最常用的遍历方式,能保证元素按顺序输出),具体步骤如下:
1. 迭代器初始化:压入左路径节点
初始化时,从根节点开始,把所有左子节点依次压入栈中——这样栈顶就是整个树的最左叶子节点(也就是有序集合的第一个元素)。
2. 每次next()的逻辑
- 弹出栈顶元素,这就是当前要返回的元素;
- 如果这个元素有右子节点,就把右子节点的所有左子节点依次压入栈(因为中序遍历是「左→根→右」,处理完根之后要接着处理右子树的最左节点)。
代码示例(结合二叉树节点结构)
假设你的树节点定义是这样的:
struct TreeNode { int value; TreeNode* left; TreeNode* right; TreeNode(int val) : value(val), left(nullptr), right(nullptr) {} };
那迭代器可以这么实现:
class TreeSetIterator { private: std::stack<TreeNode*> traverseStack; // 辅助函数:把某个节点的所有左子节点压入栈 void pushAllLeft(TreeNode* node) { while (node != nullptr) { traverseStack.push(node); node = node->left; } } public: // 构造函数:初始化时压入根节点的所有左路径 TreeSetIterator(TreeNode* root) { pushAllLeft(root); } // 返回下一个有序元素 int next() { TreeNode* currentNode = traverseStack.top(); traverseStack.pop(); // 处理当前节点的右子树左路径 pushAllLeft(currentNode->right); return currentNode->value; } // 判断是否还有未遍历的元素 bool hasNext() { return !traverseStack.empty(); } };
逻辑解释
- 初始化后,栈里保存的是从根到最左叶子的路径,第一个
next()会返回最左叶子(有序集合的第一个元素); - 弹出节点后,把它的右子树的左路径压栈,这样下一次
next()就会处理右子树的最左节点,正好符合中序遍历的顺序; - 栈里的元素天然就是需要回溯的父节点,比如当你遍历完左叶子节点,栈顶就是它的父节点,弹出后就能继续处理父节点的右子树——完美解决了你说的回溯难题!
扩展:如果是多叉树怎么办?
如果你的树是多叉结构(每个节点有多个子节点),思路类似:
- 初始化时把根节点压栈,然后逆序压入它的所有子节点(保证左到右的遍历顺序);
next()弹出栈顶元素后,再逆序压入该元素的所有子节点即可。
注意事项
- 迭代器的失效问题:如果在迭代过程中修改树结构(插入/删除节点),迭代器的状态会混乱,作业里如果没要求处理这个可以暂时忽略;
- 空树判断:初始化时要处理根节点为
nullptr的情况,避免栈操作出错。
内容的提问来源于stack exchange,提问作者Doe J
相关产品推荐
相关产品推荐

