中序递归遍历bst时,若当前节点值小于low则只递归右子树,大于high则只递归左子树,否则先递归左子树、访问节点、再递归右子树,实现高效区间提取。

如何用递归中序遍历提取 [low, high] 区间内的节点值
二叉搜索树(BST)的中序遍历天然有序,这是区间提取最直接的突破口。但盲目遍历整棵树效率低——尤其当树很大、区间很小时,必须剪枝。
关键在于利用 BST 性质:left subtree 。一旦当前节点值 <code>val 小于 low,左子树全小于 low,可跳过;同理,若 val > high,右子树全大于 high,也可跳过。
- 只在
low 时收集该节点值 - 左子树仅在
val > low时递归(否则整个左子树都无效) - 右子树仅在
val 时递归(否则整个右子树都无效)
void rangeQuery(TreeNode* root, int low, int high, vector<int>& res) {
if (!root) return;
if (root->val > low) rangeQuery(root->left, low, high, res);
if (root->val >= low && root->val val);
if (root->val right, low, high, res);
}</int>
std::vector<int></int> 返回 vs. 引用传入:为什么推荐后者
如果函数定义为 vector<int> rangeQuery(...)</int> 并每次 return res,会触发多次 vector 拷贝(尤其递归深度大时),性能明显下降。C++11 后虽有 RVO 和移动语义缓解,但不保证生效,且可读性差。
- 引用传入
vector<int>& res</int>是零拷贝、明确意图的标准做法 - 调用方控制内存生命周期,避免临时对象析构风险
- 若需链式调用,再包一层 wrapper 函数构造并返回 vector 即可
迭代实现时如何避免栈溢出或逻辑错乱
递归写法简洁,但极端偏斜树(如退化为链表)可能导致栈溢出。迭代版需手动维护栈,且剪枝逻辑比递归更易出错。
核心难点是:不能简单压入所有节点再判断范围,必须边访问边决策是否入栈左/右子节点。
- 用
stack<treenode></treenode>模拟递归调用栈 - 对每个出栈节点,先按 BST 性质决定是否访问其左/右子树:
→ 若node->val > low,才将node->left入栈
→ 若node->val ,才将 <code>node->right入栈 - 注意:入栈顺序要和中序一致(左→根→右),所以先压右、再压左,才能让左子树先出栈
重复值处理与 low/high 边界是否包含
BST 定义本身不禁止重复值(取决于实现),但标准定义通常要求“左子树 ≤ 根 ≤ 右子树”或严格小于。务必确认你所用 BST 的插入规则。
区间 [low, high] 是闭区间,代码中必须写成 >= low && 。常见错误是写成 <code>> low && ,漏掉边界值。
- 如果 BST 允许重复且分散在左右子树中,上述剪枝逻辑仍正确——只要节点值落在区间内就收录
- 若 BST 是严格 BST(无重复),则无需额外去重
- 测试时一定要覆盖
low == high、low或high恰好等于某节点值的 case
实际用的时候,最容易被忽略的是剪枝条件和中序顺序的耦合——比如误把“先访问左再判断是否压右”写成“先压右再压左”,结果顺序错乱;或者在迭代版里忘了检查 node->val > low 就压左子节点,导致无效遍历。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











