C++ 二叉搜索树详解
二叉搜索树(Binary Search Tree, BST),又称二叉排序树,是数据结构中非常经典的一种结构。它或者是空树,或者满足以下性质:
- 若左子树不空,则左子树上所有结点的值均小于或等于根结点的值
- 若右子树不空,则右子树上所有结点的值均大于或等于根结点的值
- 左右子树也分别为二叉搜索树
值得注意的是,二叉搜索树是否支持插入相等值取决于具体定义。例如 STL 中的 set 和 map 不支持重复键,而 multiset 和 multimap 支持。后续我们会看到这两种模式在代码层面的区别。
性能分析
二叉搜索树的效率高度依赖于树的形态。
- 最优情况:树接近完全二叉树,高度为 $O(\log_2 N)$。
- 最差情况:树退化为单支树(类似链表),高度为 $O(N)$。
综合来看,增删查改的时间复杂度介于 $O(\log N)$ 到 $O(N)$ 之间。这也是为什么单纯的二叉搜索树往往不够稳定,后续衍生出了 AVL 树、红黑树等平衡搜索二叉树来保证效率。
既然有了时间复杂度为 $O(\log N)$ 的二分查找,为什么还需要二叉搜索树?
二分查找的缺陷
- 需要存储在支持下标随机访问的结构中(如数组)。
- 数据必须有序。
- 插入和删除效率低,因为涉及大量数据移动。
二叉搜索树正是为了弥补二分查找在动态操作上的短板而生。

核心操作逻辑
1. 插入 (Insert)
插入过程遵循'寻找位置'的原则:
- 若树为空,新结点直接成为根节点。
- 若树不空,从根开始比较:
- 插入值 < 当前结点值:往左走
- 插入值 > 当前结点值:往右走
- 插入值 = 当前结点值:根据是否支持重复值决定(通常往右走或返回已存在)
- 找到空位置后,挂上新结点。
注意保持逻辑一致性,如果定义了相等值往右走,整个流程就不能忽左忽右。

2. 查找 (Find)
从根节点开始比较:
- 目标值大,向右;小,向左。
- 最多查找树的高度次,若走到空指针仍未找到,则不存在。
- 若支持重复值,通常要求返回中序遍历的第一个匹配项。
3. 删除 (Erase)
删除是最复杂的操作,需先确认元素存在,然后根据待删除结点 N 的子节点情况处理:
- 无孩子或只有一个孩子:直接将父节点的指针指向
N的唯一孩子(或nullptr),然后释放N。 - 有两个孩子:无法直接删除,需用。找到 左子树的最大值(最右结点)或右子树的最小值(最左结点)替代 的值,然后递归删除那个替代结点(此时替代结点必然属于上述第 1 种情况)。



