一、平衡树

知识点:

(1)平衡二叉树(Balanced Binary Tree)具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树AVL替罪羊树Treap伸展树等。 最小二叉平衡树的节点的公式如下 F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,可以参考Fibonacci数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量。

(2)对一棵查找树(search tree)进行查询/新增/删除 等动作, 所花的时间与树的高度h 成比例, 并不与树的容量 n 成比例。如果可以让树维持矮矮胖胖的好身材, 也就是让h维持在O(lg n)左右, 完成上述工作就很省时间。能够一直维持好身材, 不因新增删除而长歪的搜寻树, 叫做balanced search tree(平衡树)。平衡树有很多种, 其中有几类树维持平衡的方法。

(3)、红黑树红黑树的平衡是在插入和删除的过程中取得的。对一个要插入的数据项,插入程序要检查不会破坏树一定的特征。如果破坏了,程序就会进行纠正,根据需要更改树的结构。通过维持树的特征,保持了树的平衡。

红黑树有两个特征:

  ①节点都有颜色

  ② 在插入和删除过程中,要遵循保持这些颜色的不同排列的规则。

  红黑规则:

    1. 每一个节点不是红色的就是黑色的

    2. 根总是黑色的

    3. 如果节点是红色的,则它的子节点必须是黑色的(反之不一定成立)

    4. 从根到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点。(空子节点是指非叶节点可以接子节点的位置。换句话说,就是一个有右子节点的节点可能接左子节点的位置,或是有左子节点的节点可能接右子节点的位置)

   (4)、AVL树AVL树   ,它或者是一颗空二叉树,或者是具有下列性质的二叉树:

  ① 其根的左右子树高度之差的绝对值不能超过1;

  ② 其根的左右子树都是二叉平衡树。

  AVL树查找的时间复杂度为O(logN),因为树一定是平衡的。但是由于插入或删除一个节点时需要扫描两趟树,依次向下查找插入点,依次向上平衡树,AVL树不如红黑树效率高,也不如红黑树常用。

    (5)、Treap

  Treap是一棵二叉排序树,它的左子树和右子树分别是一个Treap,和一般的二叉排序树不同的是,Treap纪录一个额外的数据,就是优先级。Treap在以关键码构成二叉排序树的同时,还满足的性质(在这里我们假设节点的优先级大于该节点的孩子的优先级)。但是这里要注意的是Treap和二叉堆有一点不同,就是二叉堆必须是完全二叉树,而Treap并不一定是。

 

6)由来:平衡二叉树是基于二分法的策略提高数据的查找速度的二叉树的数据结构;

7)特点:

  ①平衡二叉树是采用二分法思维把数据按规则组装成一个树形结构的数据,用这个树形结构的数据减少无关数据的检索,大大的提升了数据检索的速度;平衡二叉树的数据结构组装过程有以下规则:

  ②非叶子节点只能允许最多两个子节点存在,每一个非叶子节点数据分布规则为左边的子节点小当前节点的值,右边的子节点大于当前节点的值(这里值是基于自己的算法规则而定的,比如hash值);

  

  ③平衡树的层级结构:因为平衡二叉树查询性能和树的层级(h高度)成正比、为了保证树的结构左右两端数据大致平衡降低二叉树的查询难度一般会采用一种算法机制实现节点数据结构的平衡,实现了这种算法的有比如AVL、Treap、红黑树,使用平衡二叉树能保证数据的左右两边的节点层级相差不会大于1.,通过这样避免树形结构由于删除增加变成线性链表影响查询效率,保证数据平衡的情况下查找数据的速度近于二分法查找;

 总结平衡二叉树特点:

  ①非叶子节点最多拥有两个子节点;

  ②非叶子节值大于左边子节点、小于右边子节点;

  ③树的左右两边的层级数相差不会大于1;

  ④没有值相等重复的节点;

  二叉树的优点:

  ①二叉排序树是一种比较有用的折衷方案。  数组的搜索比较方便,可以直接用下标,但删除或者插入某些元素就比较麻烦。  链表与之相反,删除和插入元素很快,但查找很慢。二叉排序树就既有链表的好处,也有数组的好处。  在处理大批量的动态的数据是比较有用。

  ②文件系统和数据库系统一般都采用树(特别是B树)的数据结构数据,主要为排序和检索的效率。二叉树是一种最基本最典型的排序树,用于教学和研究树的特性,本身很少在实际中进行应用,因为缺点太明显了(看看教科书怎么说的)。就像冒泡排序一样,虽然因为效率问题并不实用,单不失一种教学例子的好手段。

平衡二叉树都有哪些应用

  ①二叉树支持动态的插入和查找,保证操作在O(height)时间,这就是完成了哈希表不便完成的工作,动态性。但是二叉树有可能出现worst-case,如果输入序列已经排序,则时间复杂度为O(N)
平衡二叉树/红黑树就是为了将查找的时间复杂度保证在O(logN)范围内。所以如果输入结合确定,所需要的就是查询,则可以考虑使用哈希表,如果输入集合不确定,则考虑使用平衡二叉树/红黑树,保证达到最大效率

  ②平衡二叉树主要优点集中在快速查找。
如果你知道SGI/STL的set/map底层都是用红黑树(平衡二叉树的一种)实现的,相信你会对这些树大有兴趣。

 

例题:

Luogu 3369:

 

代码实现:

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=5e5+;
int js,t,opt,b,x,y,z,rt;
int v[N],p[N],s[N],c[N][];
inline int read() {
int n=,f=;char c=getchar();
while (c<''||c>'') {if(c=='-') f=-;c=getchar();}
while (c<=''&&c>='') {n=(n<<)+(n<<)+c-'';c=getchar();}
return n*f;
}
inline void up_date(int x){
s[x]=s[c[x][]]+s[c[x][]]+;
}
inline int work(int u){
v[++js]=u;
s[js]=;
p[js]=rand();
return js;
}
inline int merge(int x,int y){
if(!x||!y) return x+y;
if(p[x]<p[y]){
c[x][]=merge(c[x][],y);
up_date(x);
return x;
} else {
c[y][]=merge(x,c[y][]);
up_date(y);
return y;
}
}
inline void IUV(int now,int k,int &x,int &y){
if(!now) x=y=;
else {
if(v[now]<=k) x=now,IUV(c[now][],k,c[now][],y);
else y=now,IUV(c[now][],k,x,c[now][]);
up_date(now);
}
}
inline int IU(int now,int k){
while(true){
if(k<=s[c[now][]]) now=c[now][];
else if(k==s[c[now][]]+) return now;
else k-=s[c[now][]]+,now=c[now][];
}
}
int main() {
t=read();
rt=;
while(t--) {
opt=read(),b=read();
if(opt==) {
IUV(rt,b,x,y);
rt=merge(merge(x,work(b)),y);
} else if(opt==){
IUV(rt,b,x,z);
IUV(x,b-,x,y);
y=merge(c[y][],c[y][]);
rt=merge(merge(x,y),z);
} else if(opt==) {
IUV(rt,b-,x,y);
printf("%d\n",s[x]+);
rt=merge(x,y);
} else if(opt==) {
printf("%d\n",v[IU(rt,b)]);
} else if(opt==) {
IUV(rt,b-,x,y);
printf("%d\n",v[IU(x,s[x])]);
rt=merge(x,y);
} else if(opt==){
IUV(rt,b,x,y);
printf("%d\n",v[IU(y,)]);
rt=merge(x,y);
}
}
return ;
}

代码实现

Luogu 3391(文艺平衡树):

 

代码实现:

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e5+;
int fa[N],c[N][],s[N],w[N];
int n,m,rt,L,R;
inline int read() {
int n=,f=;char ch=getchar();
while (ch<''||ch>'') {if(ch=='-') f=-;ch=getchar();}
while (ch<=''&&ch>='') {n=(n<<)+(n<<)+ch-'';ch=getchar();}
return n*f;
}
inline void push_up(int x){
s[x]=s[c[x][]]+s[c[x][]]+;
}
inline void push_down(int x){
if(w[x]){
swap(c[x][],c[x][]);
w[c[x][]]^=,w[c[x][]]^=,w[x]=;
}
}
inline void rotate(int x,int &k){
int y=fa[x],z=fa[y],v;
if(c[y][]==x) v=;
else v=;
if(y==k) k=x;
else {
if(c[z][]==y) c[z][]=x;
else c[z][]=x;
}
c[y][v^]=c[x][v],fa[c[y][v^]]=y;
c[x][v]=y,fa[y]=x,fa[x]=z;
push_up(x),push_up(y);
}
inline void splay(int x,int &k){
while(x!=k){
int y=fa[x],z=fa[y];
if(y!=k){
if((c[y][]==x)^(c[z][]==y)) rotate(x,k);
else rotate(y,k);
}
rotate(x,k);
}
}
inline void build(int l,int r,int f){
if(l>r) return ;
int mid=(l+r)>>;
if(mid<f) c[f][]=mid;
else c[f][]=mid;
fa[mid]=f,s[mid]=;
if(l==r) return ;
build(l,mid-,mid),build(mid+,r,mid);
push_up(mid);
}
inline int find(int x,int k){
push_down(x);
int u=s[c[x][]];
if(k==u+) return x;
if(k<=u) return find(c[x][],k);
else return find(c[x][],k-u-);
}
inline void work(int l,int r){
int x=find(rt,l),y=find(rt,r+);
splay(x,rt),splay(y,c[x][]);
int z=c[y][];
w[z]^=;
}
int main(){
n=read(),m=read();
rt=(n+)/;
build(,n+,rt);
for(int i=;i<=m;++i){
L=read(),R=read();
work(L,R);
}
for(int i=;i<=n+;++i) printf("%d ",find(rt,i)-);
return ;
}

代码实现

二、二叉查找树

知识点:

二叉查找树定义:

在二叉树的基础上,每个节点有一个权值,若每个节点满足:

  1、其左子树所有权值小于等于自身权值

  2、其右子树所有权值大于等于自身权值

二叉查找树满足:按其中序遍历输出权值,那么权值不降。

二叉查找树有一个明显的缺点:

  特殊构造的数据能使树的深度达到O(n)级别,也就是每次查询或修改的最坏时间复杂度会达到O(n)。

三、Treap

知识点:

  Treap一词来源于Tree(树)与Heap(堆)的结合。

其原理是,对于每个节点,赋予一个随机权值,在构建平衡树时,使得原权值满足二叉查找树的性质,随机权值满足堆的性质,利用随机性,限制树的深度。Treap的优点为常数小。

 

cyyz: Day 6 平衡树整理的更多相关文章

  1. cyyz: Day 4 网络流整理

    Day 4 网络流的理论性知识(算了..我自己都看不下去,还是整理些例题以后复习用吧qaq): 一.PPT(主要内容)   二.搜自度娘 定义: 年,L.R. 福特和 D.R. 富尔克森等人给出了解决 ...

  2. cyyz : Day 1 数论整理

    声明:感谢修改这篇博客的dsr Day 1 先说一下上午的听课吧,哎~,简直了,简直(⊙o⊙)…咋说呢,引人入胜???No! 是昏昏欲睡好吧...一点听课欲都没有(强撑....),一上午停下来简直怀疑 ...

  3. 平衡树之伸展树(Splay Tree)题目整理

    目录 前言 练习1 BZOJ 3224 普通平衡树 练习2 BZOJ 3223 文艺平衡树 练习3 BZOJ 1588 [HNOI2002]营业额统计 练习4 BZOJ 1208 [HNOI2004] ...

  4. cyyz: Day 2 线段树知识整理

    Day 2 上午的听课,哎~昏昏欲睡好吧.. 一.扫描线 知识点: 由于多边形千变万化,要想填充多边形内部的所有像素,需要找到一种合适的规则,能够沿着一个方向,一个像素不漏地把多边形内部填满,同时不污 ...

  5. 平衡树(Splay):Splaytree POJ 3580 SuperMemo

    SuperMemo         Description Your friend, Jackson is invited to a TV show called SuperMemo in which ...

  6. 平衡树splay学习笔记#1

    这一篇博客只讲splay的前一部分的操作(rotate和splay),后面的一段博客咕咕一段时间 后一半的博客地址:[传送门] 前言骚话 为了学lct我也是拼了,看了十几篇博客,学了将近有一周,才A掉 ...

  7. 个人整理的数组splay板子,指针的写的太丑了就不放了。。

    splay的板子.. 由于被LCT榨干了..所以昨天去学了数组版的splay,现在整理一下板子.. 以BZOJ3224和3223为例题..暂时只有这些,序列的话等有时间把维修序列给弄上来!! BZOJ ...

  8. 数据结构之二叉搜索树、AVL自平衡树

    前言 最近在帮公司校招~~ 所以来整理一些数据结构方面的知识,这些知识呢,光看一遍理解还是很浅的,看过跟动手做过一遍的同学还是很容易分辨的哟~ 一直觉得数据结构跟算法,就好比金庸小说里的<九阳神 ...

  9. OI题目类型总结整理

    ## 本蒟蒻的小整理qwq--持续更新(咕咕咕) 数据结构 数据结构 知识点梳理 数据结构--线段树 推荐yyb dalao的总结--戳我 以后维护线段树还是把l,r写到struct里面吧,也别写le ...

随机推荐

  1. idea远程部署SpringBoot项目到Docker

    安装docker服务或者系统学习docker参考这篇文档:https://shimo.im/docs/fE0eJCx8IIojQXzB/ 1.配置docker的远程端口 vim /usr/lib/sy ...

  2. Golang ---json解析

    golang官方为我们提供了标准的json解析库–encoding/json,大部分情况下,使用它已经够用了.不过这个解析包有个很大的问题–性能.它不够快,如果我们开发高性能.高并发的网络服务就无法满 ...

  3. 《JAVA高并发编程详解》-Thread start方法的源码

    Thread start方法的源码:

  4. 论文笔记 : NCF( Neural Collaborative Filtering)

    ABSTRACT 主要点为用MLP来替换传统CF算法中的内积操作来表示用户和物品之间的交互关系. INTRODUCTION NeuCF设计了一个基于神经网络结构的CF模型.文章使用的数据为隐式数据,想 ...

  5. Gson含抽象类的反序列化

    Gson含抽象类的反序列化 场景描述: 反序列化A类的时候,这个类里面有一个抽象类属性B,B的实现类C里面又有一个抽象类属性D,D的实现类是E 实体类准备 public class A impleme ...

  6. css3 text-fill-color属性

    text-fill-color是什么意思呢?单单从字面上来看就是“文本填充颜色”,不过它实际也是设置对象中文字的填充颜色,和color的效果很相似.如果同时设置text-fill-color和colo ...

  7. CentOS - Eclipse安装Shelled

    一,下载Shelled: https://sourceforge.net/projects/shelled/ 二,打开Eclipse,以离线方式安装: Help->Install New Sof ...

  8. 使用TP5验证器遇到的坑

    项目中需要对字段进行验证,本人使用的是控制器验证方式.话不多说,直接上报错信息: SQLSTATE[42S02]: Base table or view not found: 1146 Table ' ...

  9. 【故障处理】 DBCA建库报错CRS-2566

    [故障处理] DBCA建库报错CRS-2566 PRCR-1071 PRCR-1006 一.1  BLOG文档结构图       一.2  前言部分   一.2.1  导读和注意事项 各位技术爱好者, ...

  10. C++(四十五) — 类型转换(static_cast、dynamic_cast 、const_cast、reinterpreter_cast)

     0.总结 (1)要转换的变量,转换前.转换后.转换后的结果. (2)一般情况下,避免进行类型转换. 1._static_cast(静态类型转换,int 转换为char) 格式:TYPE B = st ...