BST(二叉搜索树)
BST
基础芝士
给定一棵二叉树,每个节点有权值,定义“BST 性质”为:
对于树中的任意一个节点 \(x\) 都有:
- \(x\) 的权值大于 \(x\) 的左子树中任意节点的权值。
- \(x\) 的权值小于 \(x\) 的右子树中任意节点的权值。
即 \(左子树任意点的权值 < x < 右子树任意点的权值\)。
满足上述性质的二叉树即为“二叉搜索树”(BST)。可以发现,二叉搜索树的中序遍历的点权值单调递增。
一般情况下 BST 中无相同权值,当然有相同权值的也可以处理为无相同权值的。如图:

中序遍历结果为 \({1,2,3,4,5,6,7,8,9}\)。
维护操作
建立
为避免越界,一般在 BST 中插入正负无穷。仅由这两个节点构成的 BST 即为空 BST。如图:

建立的操作即为建立一个空 BST:
const int inf=1<<30;
struct bst
{
int l,r,v;
}a[N];
int tot,root;
int New(int v)
{
a[++tot].v=v;
return tot;
}
void build()
{
New(-inf),New(inf);
root=1,a[1].r=2;
}
查找
查找 BST 中是否存在权值为 \(v\) 的节点。从根节点开始,利用“BST 性质”,一层层往下查找。
设当前所在节点为 \(x\),权值为 \(y\):
- \(y=v\),则已找到。
- \(y>v\),若 \(x\) 无左儿子,则说明不存在;若 \(x\) 有左儿子,进入左子树继续查找。
- \(y<v\),若 \(x\) 无右儿子,则说明不存在;若 \(x\) 有右儿子,进入右子树继续查找。
用递归实现:
int find(int x,int v)
{
int y=a[x].v;
if(y==v) return x;
if(x==0) return 0; //若x不存在
return y>v ? find(a[x].l,v) : find(a[x].r,v);
}
用 while 实现:
int find(int v)
{
int x=root;
while(x)
{
int y=a[x].v;
if(y==v) break;
x= y>v ? a[x].l : a[x].r;
}
return x;
}
插入
在 BST 中插入一个权值为 \(v\) 的点(假设原来不存在)。
类似于查找操作:
设当前所在节点为 \(x\),权值为 \(y\):
- \(y>v\),进入左子树继续查找。
- \(y<v\),进入右子树继续查找。
- 若接下来进入的点为空,则直接建立。
用递归实现:
int insert(int &x,int v)//使用&,更新其父节点的信息
{
int y=a[x].v;
if(y==v) return ;
if(x==0)
{
x=New(v);
return ;
}
return y>v ? insert(a[x].l,v) : insert(a[x].r,v);
}
求最大/最小值
求以节点 \(x\) 为根节点的树的最大/最小值。在 BST 中,任一子树都是 BST,而 BST 的最小值一定在最左边的点上,最大值一定在最右边的点上(“BST 性质”)。如图:

则求最大值就是从 \(x\) 开始一直向左子树走直到没有左子树,求最小值就是从 \(x\) 开始一直向右子树走直到没有右子树,当然要注意避开正负无穷。
int get_min(int x)
{
while(a[x].l) x=a[x].l;
return x;
}
int get_max(int x)
{
while(a[x].r) x=a[x].r;
return x;
}
求前驱/后继
设节点为 \(x\),权值为 \(y\)。
- \(x\) 的前驱:指中序遍历 BST 后,位于 \(x\) 前的第一个点,即满足 \(v<y\) 的最大的 \(v\) 所对应的节点。
- \(x\) 的后继:指中序遍历 BST 后,位于 \(x\) 后的第一个点,即满足 \(v>y\) 的最小的 \(v\) 所对应的节点。
因此,求 \(x\) 的前驱即求 \(x\) 左子树中的最大值,求 \(x\) 的后继即求 \(x\) 右子树中的最小值。
int get_pre(int x)
{
return get_max(a[x].l);
}
int get_ne(int x)
{
return get_min(a[x].r);
}
若给出的是 \(y\):
int get_pre(int u,int v)
{
if(u==0) return -inf;
if(a[u].v>=v) return get_pre(a[u].l,v);//先找到左子树
return max(a[u].v,get_pre(a[u].r,v));//再找到最大值
}
int get_ne(int u,int v)
{
if(u==0) return inf;
if(a[u].v<=v) return get_ne(a[u].r,v);//先找到右子树
return min(a[u].v,get_ne(a[u].l,v));//再找最小值
}
删除
从 BST 中删除权值为 \(v\) 的节点 \(x\)。
思考如何在删除 \(x\) 后能维护 BST。
- 若 \(x\) 的儿子个数小于2,则直接用 \(x\) 的儿子代替 \(x\) 的位置,与 \(x\) 的父节点相连。
- 若 \(x\) 的儿子个数等于2,考虑删除后,应该是 \(x\) 的后继 \(next\) 代替它的位置,也就是要先删除 \(next\),再用 \(next\) 代替 \(x\)。而且 \(next\) 无左儿子,因为 \(next\) 是 \(x\) 右子树的最小值。所以,用 \(next\) 的右儿子代替 \(next\) 的位置,再用 \(next\) 代替 \(x\) 的位置。
void remove(int v)
{
int &x=root;//同时修改x父节点的信息
while(x)
{
int y=a[x].v;
if(y==v) break;
x= y>v ? a[x].l : a[x].r;
}
if(x==0) return;
if(a[x].l==0) x=a[x].r;
else if(a[x].r==0) x=a[x].l;
else
{
int next=get_ne(x);
remove(a[next].v);
a[next].l=a[x].l,a[next].r=a[x].r;
x=next;
}
}
结语
BST 中每一次操作的期望复杂度为 \(O(\log{n})\),但 BST 容易退化。当 BST 为一条链时,复杂度为 \(O(n)\)。为了解决该问题,出现了各种平衡二叉树,请看:
tips
点权值中需满足“BST性质”的称为“关键码”,平衡二叉树中会区分开。
BST(二叉搜索树)的更多相关文章
- 数据结构中很常见的各种树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)
数据结构中常见的树(BST二叉搜索树.AVL平衡二叉树.RBT红黑树.B-树.B+树.B*树) 二叉排序树.平衡树.红黑树 红黑树----第四篇:一步一图一代码,一定要让你真正彻底明白红黑树 --- ...
- [LeetCode] Serialize and Deserialize BST 二叉搜索树的序列化和去序列化
Serialization is the process of converting a data structure or object into a sequence of bits so tha ...
- bst 二叉搜索树简单实现
//数组实现二叉树: // 1.下标为零的元素为根节点,没有父节点 // 2.节点i的左儿子是2*i+1:右儿子2*i+2:父节点(i-1)/2: // 3.下标i为奇数则该节点有有兄弟,否则又左兄弟 ...
- 数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)
树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: BST树 ...
- [LeetCode] Minimum Absolute Difference in BST 二叉搜索树的最小绝对差
Given a binary search tree with non-negative values, find the minimum absolute difference between va ...
- 浅析BST二叉搜索树
2020-3-25 update: 原洛谷日报#2中代码部分出现一些问题,详情见此帖.并略微修改本文一些描述,使得语言更加自然. 2020-4-9 update:修了一些代码的锅,并且将文章同步发表于 ...
- 530 Minimum Absolute Difference in BST 二叉搜索树的最小绝对差
给定一个所有节点为非负值的二叉搜索树,求树中任意两节点的差的绝对值的最小值.示例 :输入: 1 \ 3 / 2输出:1解释:最小绝对差为1,其中 2 和 1 的差的绝对值为 ...
- LeetCode #938. Range Sum of BST 二叉搜索树的范围和
https://leetcode-cn.com/problems/range-sum-of-bst/ 二叉树中序遍历 二叉搜索树性质:一个节点大于所有其左子树的节点,小于其所有右子树的节点 /** * ...
- Leetcode938. Range Sum of BST二叉搜索树的范围和
给定二叉搜索树的根结点 root,返回 L 和 R(含)之间的所有结点的值的和. 二叉搜索树保证具有唯一的值. 示例 1: 输入:root = [10,5,15,3,7,null,18], L = 7 ...
- 标准BST二叉搜索树写法
本人最近被各种数据结构的实验折磨的不要不要的,特别是代码部分,对数据结构有严格的要求,比如写个BST要分成两个类,一个节点类,要给树类,关键是所以操作都要用函数完成,也就是在树类中不能直接操作节点,需 ...
随机推荐
- 【pwn】[SWPUCTF 2021 新生赛]nc签到 --shell过滤字符
附件下载打开: import os art = ''' (( "####@@!!$$ )) `#####@@!$$` )) (( '####@!!$: ...
- 文心一言 VS 讯飞星火 VS chatgpt (136)-- 算法导论11.3 2题
二.用go语言,假设将一个长度为r的字符串散列到m 个槽中,并将其视为一个以 128 为基数的数,要求应用除法散列法.我们可以很容易地把数 m 表示为一个 32 位的机器字,但对长度为r的字符串,由于 ...
- Python 潮流周刊#27:应该如何处理程序的错误?
你好,我是猫哥.这里每周分享优质的 Python.AI 及通用技术内容,大部分为英文.本周刊开源,欢迎投稿.另有电报频道作为副刊,补充发布更加丰富的资讯. 产品推荐 Walles.AI 是一款适用于所 ...
- 基于.net6.0 Fast.ORM 已全面支持AOT编译 所有Api均测试通过
Fast Framework 作者 Mr-zhong 代码改变世界.... 一.前言 Fast Framework 基于NET6.0 封装的轻量级 ORM 框架 支持多种数据库 SqlServer O ...
- 图片转换网站推荐(BMP格式作业)
做选做作业时我发现我的PS不能保存为BMP格式 只好网上搜索,发现了一个不错的免费网站 图片转换
- 七天.NET 8操作SQLite入门到实战 - 第五天引入SQLite-net ORM并封装常用方法(SQLiteHelper)
前言 上一章节我们搭建好了EasySQLite的前后端框架,今天我们的主要任务是在后端框架中引入SQLite-net ORM并封装常用方法(SQLiteHelper). 七天.NET 8操作SQLit ...
- Axure实战应用:Axure设计可视化大屏!
Axure是一款功能强大的原型设计工具,可以用于设计可视化大屏.设计一个有效的可视化大屏需要考虑多个方面,包括布局规划.信息展示.交互设计等. 以下是一个详细的描述,希望对你有所帮助. 第一部分:可视 ...
- 神经网络入门篇:详解参数VS超参数(Parameters vs Hyperparameters)
参数 VS 超参数 什么是超参数? 比如算法中的learning rate \(a\)(学习率).iterations(梯度下降法循环的数量).\(L\)(隐藏层数目).\({{n}^{[l]}}\) ...
- 使用Visual Studio 2022 创建lib和dll并使用
对于一个经常写javaWeb的人来说,使用Visual Studio似乎没什么必要,但是对于使用ffi的人来说,使用c或c++编译器,似乎是必不可少的,下面我将讲述如何用Visual Studio 2 ...
- controller加载控制与业务bean加载控制
1.因功能的不同,如何避免Spring错误加载到SpringMVC的bean--加载Spring控制的bean的时候排除掉SpringMVC控制的bean. package com.itheima.c ...