二叉搜索树的范围查询是给定闭区间[low, high],返回所有值落在该区间的节点;它利用BST左小右大性质剪枝跳过整棵无关子树,平均时间复杂度为O(k + log n),而非暴力遍历的O(n)。

什么是二叉搜索树的范围查询
范围查询就是给定一个闭区间 [low, high],返回 BST 中所有值落在该区间内的节点。它不是简单遍历全部节点再过滤——那样是 O(n),而利用 BST 左小右大的性质,可以剪枝跳过整棵子树,平均做到 O(k + log n),其中 k 是结果数量。
递归实现时如何避免重复访问和漏节点
关键在于:只在当前节点值处于 [low, high] 内时才加入结果;但左右子树是否递归,不能只看当前节点,而要看区间与子树可能取值范围是否有交集。
- 若
root->val >= low,左子树仍可能含有效节点(因为左子树最大值是root->val - 1),所以要递归左子树 - 若
root->val ,右子树仍可能含有效节点(因为右子树最小值是 <code>root->val + 1),所以要递归右子树 - 即使
root本身不在区间内,也不能跳过某侧子树——比如root->val ,但右子树仍可能有 ≥ <code>low的节点
示例代码片段:
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 <= high) res.push_back(root->val);
if (root->val <= high) rangeQuery(root->right, low, high, res);
}迭代写法中栈里存什么、什么时候 push/pop
迭代不是简单用栈模拟中序,而是带条件的 DFS:栈中每个元素是待检查的节点指针,但入栈前必须确认该节点所在子树与 [low, high] 有交集。
立即学习“C++免费学习笔记(深入)”;
- 初始把
root入栈 - 每次 pop 后,若节点值在范围内就加入结果
- 左子节点仅当
node->val > low时才入栈(否则整个左子树都 low) - 右子节点仅当
node->val < high时才入栈(否则整个右子树都 >high)
注意:这里用的是 > low 和 < high,不是 >=/<=,因为子树边界由父节点决定,严格不等才能保证剪枝安全。
遇到空节点或非法输入怎么处理
标准 BST 范围查询不依赖节点是否为空指针以外的校验——nullptr 直接跳过即可。但实际工程中容易踩两个坑:
- 传入的
low > high:应提前返回空结果,否则逻辑混乱(比如rangeQuery(root, 10, 5, res)) - 节点值类型为
long long或自定义类型时,比较操作符必须已正确定义,否则if (val >= low)编译失败或行为未定义 - 如果 BST 存在重复值,且要求返回所有重复节点,则无需额外去重逻辑;但如果只想要唯一值,得在收集后用
std::set去重——这会改变时间复杂度
最常被忽略的一点:范围查询本身不修改树结构,但如果你在遍历中顺便做删除或插入,就必须加锁或确保单线程——BST 非线程安全。


















