二叉搜索树
二叉搜索树
基本概念
二叉搜索树(Binary Search Tree, BST)是一种特殊的二叉树,它满足:对于任意节点,其左子树中所有节点的值都小于该节点的值,右子树中所有节点的值都大于该节点的值。左右子树也分别为二叉搜索树。中序遍历 BST 可以得到一个递增的有序序列。
数据结构的三要素
- 逻辑结构
- 树形结构,但节点之间具有“左小右大”的约束关系,本质上是一种动态有序表。
- 存储结构
- 链式存储:每个节点包含数据域、左孩子指针、右孩子指针。也可使用数组顺序存储(需按完全二叉树编号,但会浪费空间)。
- 数据的运算
- 查找(search)、插入(insert)、删除(delete)、求最大值/最小值、求前驱/后继、范围查询(range query)等。
费曼理解
想象你有一本按字母顺序排列的英语词典。你打开中间一页,看到单词 “M”。如果要查 “Apple”,你会往左翻(因为 A < M);如果要查 “Zoo”,你会往右翻(Z > M)。每次翻页后,你只关注剩下的一半区域,就像二分查找。二叉搜索树就是这种思想在树结构上的体现:每个节点就像一个“分界点”,左子树是它左边那一半,右子树是右边那一半。插入新单词时,同样通过比较大小决定往左还是往右,直到找到空位置放进去。
内部实现:
1 | def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]: |
复杂度分析:
| 操作 | 平均时间复杂度 | 最坏时间复杂度(链状树) | 空间复杂度(递归栈) |
|---|---|---|---|
| 查找 | O(log n) | O(n) | O(log n) / O(n) |
| 插入 | O(log n) | O(n) | O(log n) / O(n) |
| 删除 | O(log n) | O(n) | O(log n) / O(n) |
| 中序遍历 | O(n) | O(n) | O(log n) / O(n) |
优化方法:使用平衡二叉搜索树(如 AVL 树、红黑树)可将最坏情况时间复杂度降至 O(log n)。
应用场景:
- 经典问题:符号表(Symbol Table)、动态集合的快速查找与有序遍历。例如 C++ 的
std::set/std::map、Java 的TreeSet/TreeMap通常基于红黑树(平衡 BST)实现。 - 数据库索引:虽然大型数据库多用 B 树 / B+ 树(多路平衡搜索树),但其核心思想来源于 BST,通过降低树高来减少磁盘 I/O。
- 文件系统:某些文件系统的目录项管理使用树形结构(如 ext4 的 HTree 基于哈希和树)。
- 与经典结构对比:
- LRU 缓存(
HashMap + DoublyLinkedList)解决的是访问顺序淘汰,而 BST 解决的是有序存储与对数时间查找,两者侧重点不同。 - Redis 有序集合(跳表)与平衡 BST 功能相似(有序、对数时间),但跳表实现更简单且支持范围查询,Redis 因此选用跳表而非红黑树。
- LRU 缓存(
- 微机原理相关:递归实现查找/插入时,每层递归都会在栈上分配帧(保存参数、局部变量、返回地址)。当树严重不平衡(退化为链表)时,递归深度达到 O(n),可能导致栈溢出。理解内存布局有助于预估递归调用对栈空间的需求,并在必要时改为迭代实现。
相关
1 | TABLE without id file.link AS "题目名称", 数据结构,date |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!










