直接遍历不是好办法,因为bst的最左节点即最小值、最右节点即最大值,只需o(h)时间沿左/右路径查找;若用中序遍历再取首尾,则退化为o(n),尤其退化成链表时性能严重下降。

为什么直接遍历不是好办法
二叉搜索树(BST)的结构特性决定了最左节点一定是最小值,最右节点一定是最大值——不需要中序遍历全树。一旦写成 inorderTraversal(root) 再取首尾,时间复杂度就从 O(h) 退化到 O(n),尤其在退化成链表时(h ≈ n),性能损失明显。
真正高效的定位只依赖树高 h,也就是从根出发一路向左或向右,每步只比较一次指针是否为空。
找最小值:一直往左走到底
BST 的左子树所有节点都小于当前节点,所以最小值必然在最深的左叶子处。注意边界:空树应返回特殊值(如 std::nullopt 或抛异常),不能盲目解引用 nullptr。
实操建议:
- 用迭代比递归更稳妥,避免深树导致栈溢出
- 若使用
std::optional<int></int>返回,空树时直接 returnstd::nullopt - 不要在循环里重复判断
node->left == nullptr后还继续走——要提前 break 或用 while 条件控制
std::optional<int> findMin(Node* root) {
if (!root) return std::nullopt;
while (root->left) root = root->left;
return root->val;
}</int>
找最大值:一直往右走到底
逻辑对称,但容易漏掉一个细节:最大值不一定是叶子节点,而是「最右路径上的最后一个非空节点」。例如某个节点只有右子树、右子树又只有右子树……直到 nullptr 前一个才是答案。
常见错误现象:
- 写成
while (root->right != nullptr)却忘了初始 root 为空,触发段错误 - 返回前没检查
root是否为nullptr,尤其在封装成成员函数时,调用者可能传入空this - 和最小值混用同一套变量名,在调试时互相覆盖
std::optional<int> findMax(Node* root) {
if (!root) return std::nullopt;
while (root->right) root = root->right;
return root->val;
}</int>
插入/删除后还能直接用这套逻辑吗
可以,只要 BST 性质始终被维护。但要注意:某些实现中,删除操作若采用“用前驱/后继替换再删”,会改变局部结构,但整棵树仍满足 BST 定义——所以 findMin/findMax 依然有效。
关键点在于:
- 这两个函数不依赖父指针、不依赖节点计数,只依赖 left/right 指针走向
- 它们对红黑树、AVL 等自平衡 BST 同样适用(因为平衡操作不破坏 BST 性质)
- 但如果树被手动破坏(比如错把右孩子赋给 left 字段),结果就不可信了——得先保证建树逻辑正确
实际中最容易被忽略的是空指针检查的位置:有人把 if (!root) 放在 while 循环里,导致多一次无效判断;也有人完全省略,靠上层兜底,结果一测空树就崩。安全做法是入口立刻判空,不假定调用方一定守规矩。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











