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. javascript 对象,函数,原型和 this

    1.对象 在javascript里,一切都是对象,包括函数自身(不是指具体的函数,而是指"Function"这个东东).例如: var fun1=new Function(&quo ...

  2. lock、tryLock和lockInterruptibly的差別

    lock():若lock被thread A取得,thread B会进入block状态,直到取得lock:tryLock():若当下不能取得lock,thread就会放弃,可以设置一个超时时间参数,等待 ...

  3. Windbg断点调试.net程序

    程序员都知道,在生产环境中,如果没有系统日志,对问题的分析将非常的困难.即使有日志,有时候也会因为日志记录的不全面,而导致问题不能分析清楚.其实,Windbg里面有Live Debug功能,正好可以借 ...

  4. 基础知识---const、readonly、static

    const:静态常量,也称编译时常量(compile-time constants),属于类型级,通过类名直接访问,被所有对象共享! a.叫编译时常量的原因是它编译时会将其替换为所对应的值: b.静态 ...

  5. springboot: xercesImpl.jar和xml-apis.jar (系统找不到指定的文件)

    springboot内置的tomcat为8.5.23, tomcat在8.5.2 中 修改了加载jar的方式,8.5.2 版本会解析jar中MANIFEST.MF文件,当该文件包含class-path ...

  6. 百度前端技术学院task1 总结

    1.居中:当使用text-align或者vatical-align无法达到居中的时候,如果知道元素的大小,可以采用先设为left或right为50%,再设置margin-left或者margin-ri ...

  7. 你知道Object中有哪些方法及其作用吗?

    一.引言二.Object方法详解1.1.registerNatives()1.2.getClass()1.2.1.反射三种方式:1.3.hashCode()1.4.equals()1.4.clone( ...

  8. 分布式任务调度平台XXL-JOB快速使用与问题总结

    1.XXL-JOB简介 XXL-JOB is a lightweight distributed task scheduling framework. It's core design goal is ...

  9. NET 在一个数组中查找另一个数组所在起始位置(下标从0开始,未找到返回-1)

    问题: 如果 search 在 dist 中顺序出现而不要求连续出现,那代码应该如何修改?如何计算这种匹配的可能性? 数组 search=[5,4,6],在数据 dist=[1,5,5,4,3,4,5 ...

  10. 【翻译】asp.net core 3.0基本概念

    这篇文章描述了开发asp.net core所需要掌握的基本概念. 原文地址:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/?vie ...