二叉搜索树(BST)详解:原理、操作与实现
在计算机科学中,二叉搜索树(Binary Search Tree,简称 BST)是一种非常重要的数据结构,它在保持数据有序的同时,支持高效的查找、插入和删除操作。本文将深入讲解二叉搜索树的定义、性质、基本操作及其 JavaScript 实现。
一、什么是二叉搜索树?
二叉搜索树(BST)是一种特殊的二叉树,满足以下递归定义:
-
它是一棵空树;或
-
它由一个根节点、一棵左子树和一棵右子树组成,且:
- 左子树中所有节点的值 严格小于 根节点的值;
- 右子树中所有节点的值 严格大于 根节点的值;
- 左子树和右子树本身也都是二叉搜索树。
注意:通常约定 BST 中不允许重复值。若需支持重复,可约定“左 ≤ 根 < 右”等变体,但标准定义要求严格大小关系。
这种结构性质使得 BST 具备天然的有序性,从而支持高效的搜索操作。
二、时间复杂度分析
| 操作 | 平均时间复杂度 | 最坏时间复杂度 |
|---|---|---|
| 查找 | O(log n) | O(n) |
| 插入 | O(log n) | O(n) |
| 删除 | O(log n) | O(n) |
- 平均情况:当树接近“平衡”(如完全二叉树)时,高度约为 log n,操作效率高。
- 最坏情况:当插入的数据已排序(如 1,2,3,4,5),BST 退化为链表,高度为 n,性能急剧下降。
因此,在实际应用中常使用自平衡二叉搜索树(如 AVL 树、红黑树)来避免退化。
三、核心操作实现(JavaScript)
1. 节点定义
javascript
编辑
class TreeNode {
constructor(val) {
this.val = val;
this.left = null;
this.right = null;
}
}
2. 查找(Search)
从根开始,根据目标值与当前节点值的大小关系,决定向左或向右递归。
javascript
编辑
function search(root, target) {
if (!root) return null; // 未找到
if (root.val === target) {
return root;
} else if (root.val > target) {
return search(root.left, target);
} else {
return search(root.right, target);
}
}
示例:
search(root, 7)将返回值为 7 的节点。
3. 插入(Insert)
插入新节点时,始终将其作为叶子节点插入,以维持 BST 性质。
javascript
编辑
function insertIntoBST(root, val) {
if (!root) {
return new TreeNode(val); // 创建新节点
}
if (val < root.val) {
root.left = insertIntoBST(root.left, val);
} else {
root.right = insertIntoBST(root.right, val);
}
return root;
}
注意:该函数返回新的根节点(在递归回溯中重建引用)。
4. 删除(Delete)
删除是 BST 中最复杂的操作,需分三种情况处理:
情况 1:待删节点是叶子节点
- 直接删除,返回
null。
情况 2:待删节点只有一个子树
- 用其唯一子节点替代它。
情况 3:待删节点有两个子树
- 找到左子树的最大值(前驱)或右子树的最小值(后继);
- 用该值替换当前节点的值;
- 然后递归删除那个前驱或后继节点(它最多只有一个子树)。
javascript
编辑
function deleteNode(root, key) {
if (!root) return null;
if (key < root.val) {
root.left = deleteNode(root.left, key);
} else if (key > root.val) {
root.right = deleteNode(root.right, key);
} else {
// 找到要删除的节点
if (!root.left && !root.right) {
return null; // 情况1:叶子节点
} else if (root.left) {
// 情况3:优先用左子树最大值(前驱)
const maxLeft = findMax(root.left);
root.val = maxLeft.val;
root.left = deleteNode(root.left, maxLeft.val);
} else {
// 情况2 或 情况3(无左子树,用右子树最小值)
const minRight = findMin(root.right);
root.val = minRight.val;
root.right = deleteNode(root.right, minRight.val);
}
}
return root;
}
function findMax(node) {
while (node.right) node = node.right;
return node;
}
function findMin(node) {
while (node.left) node = node.left;
return node;
}
注:上述代码中有一个笔误——
root.rigth应为root.right,已在修正版本中更正。
四、示例树结构
构建如下 BST:
text
编辑
6
/ \
3 8
/ \ / \
1 4 7 9
- 查找
7:路径为 6 → 8 → 7,成功找到。 - 插入
5:成为 4 的右孩子。 - 删除
3:用左子树最大值1或右子树最小值4替代(此处用4),然后删除原4节点。
五、总结
二叉搜索树是一种兼具有序性与高效操作的数据结构,广泛应用于数据库索引、集合实现、符号表等场景。尽管其最坏性能不佳,但通过引入平衡机制(如 AVL、红黑树),可保证 O(log n) 的稳定性能。
掌握 BST 的三大操作(查找、插入、删除)是理解更高级树结构的基础。建议动手实现并调试上述代码,加深对递归与指针操作的理解。