二叉搜索树(BST)也叫二叉排序树,核心规则就一条:左子树所有节点值 ≤ 根,右子树所有节点值 ≥ 根。空树也算。相等值怎么处理看场景——STL 的 map/set 不允许重复键,multimap/multiset 允许。

性能:理想很丰满,现实可能很骨感
最优情况是树接近完全二叉树,高度 $\log_2 N$,查找、插入、删除都是 $O(\log N)$。但最差时退化成一条链,高度变成 $N$,所有操作跌到 $O(N)$。这也是为什么后来会搞出 AVL、红黑树之类的平衡树——靠自平衡把复杂度死死摁在 $O(\log N)$。

为什么有了二分查找还要用二叉搜索树?
二分查找查得快,但数据必须存在支持随机访问的有序结构里(比如数组)。一涉及插入、删除,元素就得搬家,开销太大。二叉搜索树就是为动态数据而生的。
插入:一路比下去,找到空位就塞
过程很直接:从根开始,比当前节点大往右,小往左,碰到空位就插入新节点。如果支持重复键,约定好相等时统一往左或往右就行。
比如数组 {8, 3, 1, 10, 6, 4, 7, 14, 13} 依次插入,下面这张图展示了插入 16 的过程。

查找:沿着路径走,最多树高次
同样从根开始比较。目标比当前节点大就走右子树,小就走左子树,走到空还没找到就是没有。如果不允许重复,找到了就可以返回;如果允许重复(multiset 那种),通常要求返回中序遍历的第一个。
删除:最麻烦的环节
先找到要删的节点,然后分几种情况:
- 左右子树都空——直接删,让父节点对应指针置空。
- 只有一个孩子——把孩子交给父节点,再删自己。
- 两个孩子都在——不能直接删,得找个替身。
实际实现时,情况 1 和 2 可以合并:空孩子也当成一个特殊的孩子指针。真正的难点在情况 3。
两个孩子时的'替代法'
找一个节点替换到要删的位置,这个替身必须是左子树的最大节点(最右边)或者右子树的最小节点(最左边)。因为它们放到当前位置后,整棵树仍然满足 BST 性质。
具体做法:交换待删节点和替身节点的值,然后转而去删那个替身。替身节点最多只有一个孩子(因为是最左或最右),删它就回到了简单情况。



