什么是二叉查找树(BST)

1. 什么是BST

对于二叉树中的每个节点X,它的左子树中所有项的值都小于X中的项,它的右子树中所有项的值大于X中的项。这样的二叉树是二叉查找树。

以上是一颗二叉查找树,其特点是:

(1)若它的左子树不为空,则左子树上的所有节点的值都小于它的根节点的值;

(2)若它的右子树不为空,则右子树上所有节点的值都大于它的根节点的值;

(3)其他的左右子树也分别为二叉查找树;

(4)二叉查找树是动态查找表,在查找的过程中可见添加和删除相应的元素,在这些操作中需要保持二叉查找树的以上性质。

2. 二叉查找树的定义

根据二叉查找树的要求,我们首先让BinaryNode实现Comparable接口。


// 树节点
class BinaryNode implements Comparable { Integer element; BinaryNode left; BinaryNode right; public BinaryNode{ } public BinaryNode(Integer element, BinaryNode left, BinaryNode right) {
this.element = element;
this.left = left;
this.right = right;
} @Override
public int compareTo(@NonNull Object o) {
return this.element - (Integer) o;
}
}

下面我们完成对BinarySearchTree的定义(只定义关键轮廓,具体接口后续进行分析)。


public class BinarySearchTree { //定义树的根节点
BinaryNode root; public BinarySearchTree() {
this.root = null;
} public void makeEmpty() {
this.root = null;
} public boolean isEmpty() {
return this.root == null;
} // 判断是否包含某个元素
public boolean contains(Integer x) {
//TODO:后续讲解
return false;
} // 查找最小值
public BinaryNode findMin(){
//TODO:后续讲解
return null;
} // 查找最大值
public BinaryNode findMax(){
//TODO:后续讲解
return null;
} // 按照顺序插入值
public void insert(Integer x){
//TODO:后续讲解
} // 删除某个值
public void remove(Integer x){
//TODO:后续讲解
} // 打印树
public void printTree(){
//TODO:后续讲解
}
}

3. contaions操作

如果在树T中包含项X的节点,那么该操作返回true,否则返回false。

树的结构使得这种操作变得非常简单,如果T为空集,直接返回false;否则我们就对T的左子树或右子树进行递归查找,直到找到该项X。

代码实现如下:


/**
* 是否包含某个元素
* @param x 待查找对象
* @return 查找结果
*/
public boolean contains(Integer x) {
// 首次查找从根节点开始
return contains(x,root);
} private boolean contains(Integer x, BinaryNode node) {
// 根节点为空的情况,不需要再查找
if (node == null) {
return false;
} // 与当前节点进行比较
int compareResult = x.compareTo(node.element); // 小于当前节点的值,就递归遍历左子树
if (compareResult < 0) {
return contains(x, node.left);
}
// 大于当前节点的值,就递归遍历右子树
else if (compareResult > 0) {
return contains(x, node.right);
}
// 等于当前节点值,直接返回
else {
return true;
}
}

4. 查找最小节点

从根开始并且只要有左子树就向左进行,终止点就是最小元素节点。


// 查找最小值
public BinaryNode findMin() {
return findMin(root);
} private BinaryNode findMin(BinaryNode node) {
// 当前节点为null,直接返回null
if (node == null) {
return null;
} // 不存在左子树,返回当前节点
if (node.left == null) {
return node;
} // 递归遍历左子树
return findMin(node.left); }

5. 查找最大节点

从根开始并且只要有右子树就向右进行,终止点就是最大元素节点。作为与findMin的对比,findMax方法我们抛弃了常用的递归,使用了常见的while循环来查找。


// 查找最大值
public BinaryNode findMax() {
return findMax(root);
} private BinaryNode findMax(BinaryNode node) {
if (node != null) {
while (node.right != null) {
node = node.right;
}
}
return node;
}

6. insert操作

插入操作在概念上是简单的,为了将X插入树T中,我们像contains一样沿着树查找。

如果找到X,那么我们可以什么都不做,也可以做一些更新操作。

否则,就将X插入到遍历路径上的最后一个节点。(这个做法有待商榷)

代码实现如下:


public void insert(Integer x) {
root = insert(x, root);
} // 返回的插入节点的根节点
private BinaryNode insert(Integer x, BinaryNode node) {
// 如果当前节点为null,新建节点返回
if (node == null) {
return new BinaryNode(x, null, null);
}
// 与当前节点比较
int compareResult = x.compareTo(node.element); // 小于当前节点值,递归插入左子树,并将返回值设置为当前节点的left
if (compareResult < 0) {
node.left = insert(x, node.left);
} // 大于当前节点值,递归插入右子树,并将返回值设置为当前节点的right
if (compareResult > 0) {
node.right = insert(x, node.right);
} // 等于当前的值,不做任何处理
if (compareResult == 0) {
// do some update or do noting
} return node; }

7. 删除操作

正如许多数据结构一样,最难的操作是remove,一旦我们发现了要删除的元素,就要考虑几种可能的情况:

当待删除的节点为叶子节点时,直接删除。

当待删除节点只有一个儿子节点时,把儿子节点代替该节点的位置,然后删除该节点。

当待删除的节点有两个儿子节点时,一般的删除策略是用其右子树的最小的数据代替该节点的数据并递归删除那个节点(现在它是空的);因为右子树的最小节点不可能有左儿子,所以第二次Delete要容易。


// 删除某个值
public void remove(Integer x) {
remove(x, root);
} private BinaryNode remove(Integer x, BinaryNode node) {
if (node == null) {
return null;
} int compareResult = x.compareTo(node.element); if (compareResult < 0) {
node.left = remove(x, node.left);
} if (compareResult > 0) {
node.right = remove(x, node.right);
} if (compareResult == 0) { if (node.left != null && node.right != null) { node.element = findMin(node.right).element; node.right = remove(node.element, node.right); } else { node = (node.left != null) ? node.left : node.right; } } return node; }

8. 二叉查找树的局限

同样的数据,可以对应不同的二叉搜索树,如下:

二叉搜索树可能退化成链表,相应的,二叉搜索树的查找操作是和这棵树的高度相关的,而此时这颗树的高度就是这颗树的节点数n,同时二叉搜索树相应的算法全部退化成 O(n) 级别。

显然,说二叉搜索树的查找、插入、删除这三个操作都是O(lgn) 级别的,只是一个大概的估算,具体要和二叉搜索树的形状相关。但总的来说时间复杂度在o(logn)

到o(n)之间。

9. 简单总结

二叉搜索树的节点查询、构造和删除性能,与树的高度相关,如果二叉搜索树能够更“平衡”一些,避免了树结构向线性结构的倾斜,则能够显著降低时间复杂度。二叉搜索树的存储方面,相对于线性结构只需要保存元素值,树中节点需要额外的空间保存节点之间的父子关系,所以在存储消耗上要高于线性结构。

【数据结构】什么是二叉查找树(BST)的更多相关文章

  1. 查找系列合集-二叉查找树BST

    一. 二叉树 1. 什么是二叉树? 在计算机科学中,二叉树是每个结点最多有两个子树的树结构. 通常子树被称作“左子树”(left subtree)和“右子树”(right subtree). 二叉树常 ...

  2. [学习笔记] 二叉查找树/BST

    平衡树前传之BST 二叉查找树(\(BST\)),是一个类似于堆的数据结构, 并且,它也是平衡树的基础. 因此,让我们来了解一下二叉查找树吧. (其实本篇是作为放在平衡树前的前置知识的,但为了避免重复 ...

  3. 二叉查找树(BST)

    二叉查找树(BST):使用中序遍历可以得到一个有序的序列

  4. 二叉查找树BST 模板

    二叉查找树BST 就是二叉搜索树 二叉排序树. 就是满足 左儿子<父节点<右儿子 的一颗树,插入和查询复杂度最好情况都是logN的,写起来很简单.   根据BST的性质可以很好的解决这些东 ...

  5. 【查找结构 2】二叉查找树 [BST]

    当所有的静态查找结构添加和删除一个数据的时候,整个结构都需要重建.这对于常常需要在查找过程中动态改变数据而言,是灾难性的.因此人们就必须去寻找高效的动态查找结构,我们在这讨论一个非常常用的动态查找树— ...

  6. 数据结构☞二叉搜索树BST

    二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它可以是一棵空树,也可以是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它 ...

  7. 数据结构-自平衡二叉查找树(AVL)详解

    介绍: 在计算机科学中,AVL树是最先发明的自平衡二叉查找树. 在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树. 查找.插入和删除在平均和最坏情况下都是O(log n).增 ...

  8. 二叉查找树(BST)的实现

    一.二叉树介绍 二叉查找树(Binary Search Tree,BST),又称二叉排序树,也称二叉搜索树,它或者是一颗空树,或者具有如下性质的树:若它的左子树不为空,则左子树上所有节点的值都小于根节 ...

  9. K:二叉查找树(BST)

    相关介绍:  二叉查找树(英语:Binary Search Tree),也称二叉搜索树.有序二叉树(英语:ordered binary tree),排序二叉树(英语:sorted binary tre ...

  10. 3.2 符号表之二叉查找树BST

    一.插入和查找 1.二叉查找树(Binary Search Tree)是一棵二叉树,并且每个结点都含有一个Comparable的键,保证每个结点的键都大于其左子树中任意结点的键而小于其右子树的任意结点 ...

随机推荐

  1. springcloud-微服务架构基础

    一 前言 学习微服务要从基础的架构学起,首先你要有个微服务的概念才能学习对吧!!如果你都不知道啥是微服务,就一头扎进去学习,你自己也觉得自己也学不会对吧.本篇文章主要让大家快速了解基础的架构分格,以便 ...

  2. 《Dotnet9》系列-开源C# Winform控件库强力推荐

    时间如流水,只能流去不流回! 点赞再看,养成习惯,这是您给我创作的动力! 本文 Dotnet9 https://dotnet9.com 已收录,站长乐于分享dotnet相关技术,比如Winform.W ...

  3. 面试连环炮系列(十五):说说Eureka的高可用方案

    说说Eureka的高可用方案 至少3个Eureka实例才能满足高可用,配置方法如下: 准备三个节点node1,node2,node3. 在每个实例的application.xml文件里加入 eurek ...

  4. 分布式事务之解决方案(XA和2PC)

    3. 分布式事务解决方案之2PC(两阶段提交) 针对不同的分布式场景业界常见的解决方案有2PC.TCC.可靠消息最终一致性.最大努力通知这几种. 3.1. 什么是2PC 2PC即两阶段提交协议,是将整 ...

  5. Android 插件化开发(三):资源插件化

    在前面的文章中我们成功的加载了外部的Dex(Apk)并执行了插件的Bean代码.这时我们会想,能不能加载并运行插件Apk的Activity.答案当然是能,否则后续我们的研究就没意义了,但是想实现Act ...

  6. layui2.5 开关在confirm确认了之后在关/开

    <!--默认选中--> <div class="layui-form-item layui-form"> <div class="layui ...

  7. Axure5.1.0.1699 RP汉化版

    Axure是一款产品原型(Prototype)设计软件,可通过这个软件编辑一些常见的事件和在特点条件下才会触发的情况,可以快速的生成HTML Demo页面. 使用Axure的用户很多,据淘宝UED消息 ...

  8. k8s采坑记 - 证书过期之kubeadm重新生成证书

    重新生成证书 证书备份 cp -rp /etc/kubernetes /etc/kubernetes.bak 移除过期证书 rm -f /etc/kubernetes/pki/apiserver* r ...

  9. 最近学习了Http连接池

    起因 6.1大促值班发现的一个问题,一个rpc接口在0~2点用户下单高峰的时候表现rt高(超过1s,实际上针对性优化过的接口rt超过这个值也是有问题的,通常rpc接口里面即使逻辑复杂,300ms应该也 ...

  10. RDP矢量数据压缩算法

    在绘制对象边缘时涉及到了这个算法,记录一下. 该算法递归进行,首先设定一个阈值,在点集的第一个点和最后一个点间拉一条线段,找出剩下的点集中离线段最远的一个点,如果该点到线段的距离小于阈值则舍弃中间的所 ...