Computing · Data Structures
Binary Search Tree (BST)
二叉搜索树 (BST)
~ 16 min · v24
二叉搜索树 BST
cs-ds/binary-search-tree · COMP2521
0 / 5
▶ Video walkthrough
Watch on YouTube
Binary search trees in 33 seconds
Watch the short video to grasp it faster.
1 一句话定义
二叉搜索树(BST)就是一棵对每个节点都满足"左子树都比它小、右子树都比它大"的二叉树。
像查纸质字典:翻到中间,要找的词比这页小就往前半本翻、大就往后半本翻,每翻一次就砍掉一半。BST 把"二分查找"长进了树的结构里——从根开始比大小,小往左、大往右,一路走到底。树越平衡,查找越快(O(log n));长歪成一条链就退化成 O(n)。
2 模型 · 插入 / 查找 / 中序 / 删除
三种操作共用一条规律:从根开始比大小,小往左、大往右。点上面切换,点 ▶ 单步看左边树、右上代码当前行、右下"比较过程"如何联动。
BST 在代码里怎么写?——插入与查找
节点和普通二叉树一样;BST 的灵魂在 insert/search 里的那次比较:比当前小就递归进左子树,大就进右子树,走到空位就放/就判定没找到。
// 节点定义同二叉树 struct node { int value; struct node *left, *right; }; // 插入:从根往下找空位,比小走左、比大走右 node *insert(node *t, int v) { if (t == NULL) return newNode(v); // 空位 → 放新节点 if (v < t->value) t->left = insert(t->left, v); // 小 → 左 else if (v > t->value) t->right = insert(t->right, v); // 大 → 右 return t; // 相等:已存在,不重复插 } // 查找:一样的走法,命中返回 true,走到空返回 false bool search(node *t, int v) { if (t == NULL) return false; // 走到空 → 没找到 if (v == t->value) return true; // 命中 return v < t->value ? search(t->left, v) : search(t->right, v); }
插入和查找走的是同一条路(都从根比大小往下)。所以两者代价都 = 走过的层数 = 树高 O(h)。h 在平衡时是 log n,退化成链时是 n。下面"插入建树"演示就是把 50 30 70 20 40 60 80 依次插进一棵空树。
BST 演示器
代码(当前行高亮)
比较过程
提示
点 ▶ 播放,看一个值如何从根开始比大小、一路找到自己的位置。
3 核心要点 · 4 句人话看懂 BST
BST = 二叉树 + 一条"左小右大"的硬规矩。
① BST 性质:左 < 根 < 右
一句话:对每个节点,它左边整棵子树都比它小、右边整棵子树都比它大——不是只比直接孩子,是整棵子树。
这条规矩让"从根比大小往下走"能精确定位任何值。违反它(比如把 80 放到 50 左边)就不再是 BST,查找会失灵。
50
/ \
<50 >50 ← 整棵子树都满足
② 查找/插入:比大小往下走,O(h)
一句话:比当前小往左,大往右,走到空位就是"插入点 / 没找到"。代价 = 走过的层数。
查找和插入同一条路。代价正比于树高 h:平衡时 h≈log n(很快),退化成链时 h=n(和数组线性查找一样慢)。
v < t->value → 往左
v > t->value → 往右
t == NULL → 空位/没找到
③ 中序遍历 = 升序(招牌性质)
一句话:中序遍历任何 BST,结果一定从小到大排好序。反过来,这也是验证"是不是 BST"的办法。
因为中序是"左→根→右",而左全比根小、右全比根大。想得到有序数据?把它们插进 BST 再中序遍历即可。
中序(本页树) =
20 30 40 50 60 70 80 升序
④ 删除:两个孩子最麻烦
一句话:删叶子直接删;删只有一个孩子的,让孩子顶上;删有两个孩子的,要用中序后继(右子树最小)来替身。
删除有两个孩子的节点是最经典的坑:不能直接删(会断开子树),要找右子树里最小的那个(中序后继)顶替,再删掉那个后继。
删 50:找右子树最小 = 60
60 顶替 50,再删原来的 60
4 错误实验室 · 点一下亲眼看 bug
BST 最常翻车的几个点。点击卡片看症状。
① 比较方向写反
小往右、大往左 → 树建歪了,查找永远找不到
② 删两孩子节点直接删
没找后继顶替就删 → 整个子树丢失
③ 按有序插入 → 退化成链
1 2 3 4 5 顺序插 → 高度 = n,查找退化 O(n)
// 点击上方任一卡片,查看错误代码与运行效果
$ ./a.out
(等待运行...)
5 即时小测 · 5 题 + 动手例题
用上面那棵 BST。先想再点。
去做例题:二叉搜索树 · 插入与查找
去做例题
读完这节,你应该明白:
BST = 二叉树 + 一条「左小右大」的硬规矩,而这条规矩的全部意义在于——查找和插入都能"从根比大小往下走",像翻字典一样每步砍掉一半(O(h)),中序遍历还自动得到升序。但关键的另一半是:BST 的快慢完全取决于树平不平衡——按有序数据插入会退化成一条链、掉回 O(n),和没用树一样慢。那怎么强制让树保持平衡?这正是下一站 AVL 要回答的问题 ↓