二叉排序树(二叉搜索树)
二叉排序树(也称为二叉查找树)是一种特殊的二叉树,它可以用来快速查找、插入和删除节点。
二叉排序树有以下性质:
- 在二叉排序树中,左子节点的值总是小于父节点的值。
- 在二叉排序树中,右子节点的值总是大于父节点的值。
- 二叉排序树的中序遍历结果是一个单调递增的序列。
在这个例子中,我们定义了两个类:Node
类和 BinarySearchTree
类。Node
类表示二叉排序树中的一个节点,包含一个数据域和两个指针域。BinarySearchTree
类表示二叉排序树本身,包含根节点和一些操作方法。
这个类实现了二叉排序树的两个常用操作:插入和查找。插入操作使用递归实现,查找操作也是使用递归实现。
下面是java实现的版本
class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
left = null;
right = null;
}
}
class BinarySearchTree {
Node root;
public BinarySearchTree() {
root = null;
}
public void insert(int value) {
root = insertRecursive(root, value);
}
private Node insertRecursive(Node current, int value) {
if (current == null) {
return new Node(value);
}
if (value < current.value) {
current.left = insertRecursive(current.left, value);
} else if (value > current.value) {
current.right = insertRecursive(current.right, value);
} else {
return current;
}
return current;
}
public boolean search(int value) {
return searchRecursive(root, value);
}
private boolean searchRecursive(Node current, int value) {
if (current == null) {
return false;
}
if (value == current.value) {
return true;
}
return value < current.value
? searchRecursive(current.left, value)
: searchRecursive(current.right, value);
}
}
首先来看一下插入操作的流程
参数value为待插入的元素值,current为当前树的根节点
- 首先,如果当前节点为空,说明已经到达了二叉排序树的叶子节点,此时可以直接创建新节点并返回。
- 否则,如果新值小于当前节点的值,则递归调用
insertRecursive
方法,将新值插入到当前节点的左子树中。 - 如果新值大于当前节点的值,则递归调用
insertRecursive
方法,将新值插入到当前节点的右子树中。 - 如果新值等于当前节点的值,则直接返回当前节点,
查找操作
- 首先,如果当前节点为空,说明已经搜索到了二叉排序树的叶子节点,此时可以返回
false
。 - 否则,如果搜索的值等于当前节点的值,则返回
true
。 - 否则,如果搜索的值小于当前节点的值,则递归调用
searchRecursive
方法,在当前节点的左子树中继续搜索。 - 否则,递归调用
searchRecursive
方法,在当前节点的右子树中继续搜索。
删除操作(重点)
public Node deleteNode(Node root, int key) {
if (root == null) {
return null;
}
if (key < root.value) {
root.left = deleteNode(root.left, key);
} else if (key > root.value) {
root.right = deleteNode(root.right, key);
} else {
if (root.left == null) {
return root.right;
} else if (root.right == null) {
return root.left;
}
root.value = minValue(root.right);
root.right = deleteNode(root.right, root.value);
}
return root;
}
在这个例子中,我们定义了一个名为 deleteNode
的方法,它接受两个参数:根节点和要删除的结点的值。方法体内部实现了删除结点的逻辑。
这段代码的工作流程如下:
- 首先,如果根节点为空,则返回空。
- 如果要删除的结点的值小于根节点的值,则递归调用
deleteNode
方法,在根节点的左子树中继续查找要删除的结点。 - 如果要删除的结点的值大于根节点的值,则递归调用
deleteNode
方法,在根节点的右子树中继续查找要删除的结点。 - 如果要删除的结点的值等于根节点的值,则执行删除操作。
- 如果根节点没有左子树,则返回右子树。
- 如果根节点没有右子树,则返回左子树。
- 否则,找到右子树中最小的结点,并将这个结点的值赋值给根节点。然后递归调用
deleteNode
方法,在根节点的右子树中删除这个最小结点。
删除操作中用到了一个查找子树最小结点值的方法
private int minValue(Node node) {
int minv = node.value;
while (node.left != null) {
minv = node.left.value;
node = node.left;
}
return minv;
}
这段代码的工作流程如下:
首先,将最小值初始化为当前结点的值。
- 循环遍历当前结点的左子树,直到找到最小的结点。
- 返回最小的结点的值。
同样的,我们也可以实现查找二叉排序树的最大值的方法。这个方法的实现方式与查找最小值的方法类似,只是将最小值换成最大值即可。
最后,来看一下二叉排序树的应用案例
- 在数据库的索引中,二叉排序树可以用来快速查找数据。二叉排序树的查找时间复杂度为 O(log n),要比顺序查找的时间复杂度 O(n) 快得多。
-
二叉排序树还常用于实现字典树(Trie)。字典树是一种树形数据结构,用来存储字符串集合。它的每个结点都包含一个字符,并且满足二叉排序树的性质:左子树的结点代表的字符都比根节点小,右子树的结点代表的字符都比根节点大。因此,我们可以使用二叉排序树来实现字典树。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律