BST的性质

树上每个节点上有个值,这个值叫关键码

每个节点的关键码大于其任意左侧子节点的关键码,小于其任意右节点的关键码。

显然一个BST的中序遍历就是关键码单调递增的节点序列

BST的建立

为了避免越界其实好像没卵用,减少边界情况的判定,一般在BST中额外插入一个关键码为INF和-INF的节点

const int N=1000000;
struct BST
{
int l,r;//l,r分别是左右孩子的编号
int val;//关键码
}a[N];
int tot,root,INF=1<<30;
int New(int val)
{
a[++tot].val=val;
return tot;
}
void build()
{
New(-INF),New(INF);
root=1,a[1].r=2;
}

BST的检索

在BST中检索是否存在关键码为val的节点

设p为根节点

1.若p的关键码等于\(val\),直接返回

2.若p的关键码大于\(val\)

​ (1)若\(p\)的左子节点为空,则不存在

​ (2)若\(p\)的左子节点不为空,则在p的左子树中递归检索

2.若p的关键码小于\(val\)

​ (1)若\(p\)的右子节点为空,则不存在

​ (2)若\(p\)的右子节点不为空,则在\(p\)的右子树中递归检索

int get(int p,int val)
{
if(p==0) return 0;
if(val==a[p].val) return p;
return val<a[p].val ? get(a[p].l,val) : get(a[p].r,val);
}

BST的插入

在BST中插入关键码为val的节点

与BST的检索的检索过程类似,这里就不在赘述

void insert(int &p,int val)
{
if(p==0)
{
p=New(val);
return ;
}
if(val==a[p].val) return;
val<a[p].val ? insert(a[p].l,val) : insert(a[p].r,val);
}

细心的读者应该发现了p是引用的,why?

因为这里父节点的l或r值会被更新

BST求前驱/后继

这里首先赘述一下什么是前驱和后继

后继:BST中关键码大于val的最小的

前驱:BST中关键码小于val的最大的

这里以求后继为例

初始化ans为正无穷关键码的那个节点的编号。然后在BST中检索val,检索过程中不断更新ans

检索完成后有三种可能的结果

1.没有找到\(val\),那么现在ans即为所求

2.找到了\(val\),但是关键码为val的节点p没有右子树,那ans即为所求

3.找到了\(val\),而且关键码为val的节点p有右子树,那么就要从p的右孩子一直向左找

因为教育局把sm.ms图床给封了所以图片上传不了,抱歉

int getnext(int val)
{
int ans=2,p=root;
while(p)
{
if(val==a[p].val)
{
if(a[p].r>0)
{
p=a[p].r;
while(a[p].l>0) p=a[p].l;
ans=p;
}
break;
}
if(a[p].val>val&&a[p].val<a[ans].val) ans=p;
p=val<a[p].val ? a[p].l : a[p].r;
}
return ans;
}

上面的代码是用的非递归,以后有时间可能会补上递归的

前驱同理,这里不再赘述。

BST的节点删除

从BST中删除关键码为val的节点

首先检索出关键码为val的节点p来

有以下几种情况

1.如果p的子节点个数小于\(2\),则直接删除掉\(p\),并令\(p\)的子节点替代\(p\)的位置,与\(p\)的父节点相连

2.\(p\)既有左子树又有右子树,那么就找出\(val\)的后继来,显然后继没有左子树,所以直接删除后继,然后让后继的右子树代替游记,然后让后继代替\(p\)

没法传图,抱歉*2

void remove(int &p,int val)
{
if(p==0) return ;
if(val==a[p].val)
{
if(a[p].l==0) p=a[p].r;
else if(a[p].r==0) p=a[p].l;
else
{
int next=a[p].r;
while(a[next].l>0) next=a[p].l;
remove(a[p].r,a[next].val);
a[next].l=a[p].l,a[next].r=a[p].r;
p=next;
}
return ;
}
if(val<a[p].val) remove(a[p].l,val);
else remove(a[p].r,val);
}

细心的读者可能发现了,上述代码只能处理没有重复的关键值的情况,其实处理重复的关键值也很简单,这需要记录一个\(cnt\)即可

struct BST
{
int l,r;//l,r分别是左右孩子的编号
int val;//关键码
int cnt;//计数器
}a[N];

其他操作不再赘述

复杂度

显然BST一次操作复杂度为\(O(log N)\)。

但是BST容易被有序数列卡成\(O(N)\)的,这时树就变成一条链了

这是就可以用平衡树解决.....以后或许会更一篇平衡树的博客(前提是我要学会)

参考《算法竞赛进阶指南》,代码未经测试不保证正确性,如有错误还望指正(狗头保命)

平衡树

浅谈fhq\ treap

浅谈BST(二叉查找树)的更多相关文章

  1. 浅谈算法和数据结构: 七 二叉查找树 八 平衡查找树之2-3树 九 平衡查找树之红黑树 十 平衡查找树之B树

    http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html 前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的 ...

  2. HTTP协议漫谈 C#实现图(Graph) C#实现二叉查找树 浅谈进程同步和互斥的概念 C#实现平衡多路查找树(B树)

    HTTP协议漫谈   简介 园子里已经有不少介绍HTTP的的好文章.对HTTP的一些细节介绍的比较好,所以本篇文章不会对HTTP的细节进行深究,而是从够高和更结构化的角度将HTTP协议的元素进行分类讲 ...

  3. 浅谈splay(点的操作)

    浅谈splay(点的操作) 一.基本概念 splay本质:二叉查找树 特点:结点x的左子树权值都小于x的权值,右子树权值都大于x的权值 维护信息: 整棵树:root 当前根节点  sz书上所有结点编号 ...

  4. 浅谈 Java集合

    Java 集合 集合是对象的容器,定义了多个对象进行操作的常用方法,可实现数组的功能. Java集合类库所处位置:java.util.*. 与现代的数据结构类库的常见做法一样,Java集合类库也将接口 ...

  5. 浅谈 Fragment 生命周期

    版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...

  6. 浅谈 LayoutInflater

    浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...

  7. 浅谈Java的throw与throws

    转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...

  8. 浅谈SQL注入风险 - 一个Login拿下Server

    前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...

  9. 浅谈WebService的版本兼容性设计

    在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...

随机推荐

  1. python爬取电影网站信息

    一.爬取前提1)本地安装了mysql数据库 5.6版本2)安装了Python 2.7 二.爬取内容 电影名称.电影简介.电影图片.电影下载链接 三.爬取逻辑1)进入电影网列表页, 针对列表的html内 ...

  2. RBAC类在ThinkPHP中的四种使用方法

    第一类:放在登陆控制器的登陆操作中 1.RBAC::authenticate(); 用于在用户表中查找表单提交的用户名的数据,实质上就是一条用户表查寻语句,=====> return M(mod ...

  3. SQL ------------ 对表中字段的操作 alter

    ALTER TABLE 语句用于在现有表中添加.删除或修改列. 注意不同的数据库的语句有所不一样 增加和删除都基本一致. 进行修改表中字段的时候注意: 本文主要介绍  sqlserver/mysql/ ...

  4. protobuf 中import 的使用

    目录结构如下: test.proto的文件内容如下: syntax="proto2"; package com.eagle.mohrss; option java_outer_cl ...

  5. docker容器中使用rsyslogd

    rsyslogd作为CentOS:7系统自带的日志管理工具,为很多服务提供了便捷的日志管理接入方案,然而 CentOS:7的官方镜像 默认是不支持rsyslogd的.我们做个实验: 1)启动测试容器 ...

  6. Web应急:网站被批量挂黑页

    作为一个网站管理员,你采用开源CMS做网站,比如dedecms,但是有一天,你忽然发现不知何时,网站的友情链接模块被挂大量垃圾链接,网站出现了很多不该有的目录,里面全是博彩相关的网页.而且,攻击者在挂 ...

  7. 「福利」Java Swing 编写的可视化算法工程,包含树、图和排序

    之前在整理<学习排序算法,结合这个方法太容易理解了>这篇文章时,发现了一个用 Java Swing 编写的可视化算法工程,真心不错!包含了常用数据结构和算法的动态演示,先来张图感受下: 可 ...

  8. 2019-11-29-C#-反射调用私有事件

    原文:2019-11-29-C#-反射调用私有事件 title author date CreateTime categories C# 反射调用私有事件 lindexi 2019-11-29 08: ...

  9. STMP发送邮件(C#)

    记录一下使用SMTP协议发送邮件 public void Mail() { try { System.Net.Mail.SmtpClient client = new System.Net.Mail. ...

  10. P2995 [USACO10NOV]牛的照片(树状数组,逆序对)

    题目: P2995 [USACO10NOV]牛的照片Cow Photographs P4545 [USACO10NOV]奶牛的图片Cow Photographs SP7809 COWPIC - Cow ...