平衡树SPLAY

一个比线段树代码还要又臭又长的数据结构,各式各样的函数,咱也不知道别人怎么记住的,咱也不敢问

SPLAY的性质

1.某个节点的左子树全部小于此节点,右子树全部大于此节点

2.中序遍历splay输出的序列是按从小到大的顺序

(我当时忽略了性质2,以为大小关系只存在于单独的左右儿子和父节点,后来问了同学才知道,我没看过二叉排序树,我能怎么办

询问左右儿子

就是查询一下x是fa的左儿子还是右儿子

int get(int x)
{return a[a[x].fu].son[1]==x; 
}

 

更新数据

由于每次翻转之后左右儿子的信息都会改变,所以需要更新一下size

void gx(int x)
{a[x].size=a[a[x].son[0]].size+a[a[x].son[1]].size+a[x].js;
}

 

上旋

什么是上旋呢,简单来说就是儿子想当爹,然后他还成功了,也不知道这个爹会不会被气死,就是把自己父节点变成自己的一个儿子,但是对于一个有两个子节点的子节点,显然父节点没地方去,又因为需要保证平衡树的性质(左子树小于父节点小于右子树),所以肯定子节点的某一个叶节点要去给父节点当儿子,根据splay性质中的大小关系,如果子节点是父节点的左儿子那父节点就要去当子节点的右儿子,此时根据splay的性质直接让子节点的右儿子去当父节点的左儿子即可,这样就完成了一次翻转并且没有改变splay的性质,若子节点是父节点的右儿子,同理交换儿子,总结一下就是假设右旋x,x是fa的0儿子就让x的1儿子去当fa的0儿子,fa变成x的1儿子(0和1就是一个左一个右)

void sx(int x)
{int f=a[x].fu,ff=a[f].fu;int z1=get(x),z2=get(f);a[f].son[z1]=a[x].son[z1^1];  a[a[x].son[z1^1]].fu=f;a[x].son[z1^1]=f;  a[f].fu=x;a[ff].son[z2]=x;  a[x].fu=ff;gx(f);  gx(x);
}

 

双旋

我觉得双旋就是上旋中的一种特殊情况,就是子节点,父节点,祖父节点在同一条线上,这时需要先上旋父节点(据说直接上旋慢,不够优秀,而且双旋好像还可以减小期望深度,我并没有模拟),同一条线的话,特判一下就可以了,记得更新根节点

void splay(int x,int mb)
{while(a[x].fu!=mb){int f=a[x].fu,ff=a[f].fu;int z1=get(x),z2=get(f);if(ff!=mb){if(z1==z2)  sx(f);else  sx(x);}sx(x);}if(mb==0)  root=x;
}

 

几个基本操作

1.插入节点

插入的话,我觉得和权值线段树那种递归的原理差不多,遍历来找到合适的位置,加入已经有这个点就直接cnt++,如果没有的话就新建一个节点,新建之后的话把新建的点旋到根维护下树就可以了

void cr(int x)
{int dq=root,f=0;while(a[dq].w!=x&&dq!=0){f=dq;dq=a[dq].son[a[dq].w<x];}if(dq!=0)  {a[dq].js++;  gx(dq);}else{dq=++num;if(f!=0)  a[f].son[a[f].w<x]=dq;a[dq].size=1;  a[dq].js=1;a[dq].fu=f;  a[dq].w=x;}splay(dq,0);
}

 

2.删除结点

删除还是和插入一样,有两种情况,如果这个节点的个数不为一直接cnt--,然后旋到根,如果为一的话删除这个点又不能影响其他点,但是你没办法保证删除的每一个点都没有叶子节点,这个时候就需要上旋来保证删除的点没有叶子结点,具体操作就是把前驱旋到根,后继旋到前驱下面,这样的话被删除的点就变成了叶子节点,直接清零删除就可以了

void sc(int x)
{int qqq=qq(x),hjh=hj(x);splay(qqq,0);  splay(hjh,qqq);int z=a[hjh].son[0];if(a[z].js>1)  {a[z].js--;  gx(z);  splay(z,0);}else  a[hjh].son[0]=0;
}

 

3.查询某值排名

查询排名先要找到这个值在树中的位置,当然如果没有这个值的话会一直找的叶子节点(也不一定是最接近查询值的点,我运行了一下,发现他会找到第一个比这个值小的值,而不是最接近这个数的值),这种操作的话可以搜极大值和极小值来找到树中最大值和最小值,找到这个值之后就简单了,把这个值上旋到根的位置,他左边都是比他小的,右边都是比他大的,那么他左子树的size+1就是这个值的排名

int find(int x)
{int dq=root;while(a[dq].w!=x&&a[dq].son[a[dq].w<x]!=0)dq=a[dq].son[a[dq].w<x];return dq;    
}
int cpm(int x)
{splay(find(x),0);return a[a[root].son[0]].size;
}

 

关于find函数的运行结果(1为插入2为find查询)

4.查询某值的前驱/后继

x的前驱:小于x的最大的数    x的后继:大于x的最小的数

用find函数查找x,把x上旋到根的位置,由于x可能不存在,而find查到的又是第一个比他小的值,所以有可能上旋后根节点就是要查询的前驱,所以要特判,但是根据我的运行结果来说,我认为后继不需要特判,如果怕不保险,特判也无所谓,反正特判应该是肯定对的那个,如果有x这个值那么前驱就是他的左子树的最右叶子节点,同理,后继就是他右子树的最左叶子节点,一直向下搜就可以了

int qq(int x)
{splay(find(x),0);int dq=root;if(a[dq].w<x)  return dq;dq=a[dq].son[0];while(a[dq].son[1]!=0)  dq=a[dq].son[1];return  dq;
}
int hj(int x)
{splay(find(x),0);int dq=root;if(a[dq].w>x)  return dq;dq=a[dq].son[1];while(a[dq].son[0]!=0)  dq=a[dq].son[0];return dq;
}

 

5.查询第k小值

跟主席树求第k小有点相似,通过记录左右子树包含的元素个数与k进行比较,选择暴力递归左儿子或者右儿子,如果当前节点的左子树元素个数小于k,那么第k小就在右子树中,k减去左子树元素个数+当前点的cnt值(还有这个元素自己)后暴力搜索右子树,如果左子树元素个数大于k,直接搜索左子树,假如k介于左子树右子树的size之间(一定要想清为什么有范围,因为同一个值可能出现多次,导致他自己代表的值就不唯一,我死在这好久),那么当前点就是第k小

int csz(int x)
{int dq=root;while(1){int ls=a[dq].son[0];if(a[ls].size>=x)  dq=ls;else if(a[ls].size+a[dq].js<x){x-=a[ls].size+a[dq].js;dq=a[dq].son[1];}else  return a[dq].w;}
}

 

到此,普通平衡树就可以搞定了

关于插入结点那一块,虽然最后的splay执行中会更新结点,但是我还是觉得在直接更新cnt之后更新一下节点信息比较好

现在思路是理出来了,也不知道代码能不能打下来(我依旧是个蒟蒻)

第一次完整的整理了一个知识点还有点兴奋

转载于:https://www.cnblogs.com/hzjuruo/p/11110279.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/274838.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

POJ 2696 计算表达式的值

时间限制: 1000ms内存限制:65536kB描述有些语言中表达式的运算符使用字符串表示&#xff0c;例如用mul代表*&#xff0c;用div代表/&#xff0c;用add代表&#xff0c;用sub代表-&#xff0c;用mod代表%。输入第一行为表达式的个数n。其余n行每行一个表达式&#xff0c;表达式由…

为支持两个语言版本,我基于谷歌翻译API写了一款自动翻译的 webpack 插件

大家好&#xff0c;我是若川。持续组织了6个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列本文来…

全球 化 化_全球化设计

全球 化 化重点 (Top highlight)Designing for a global audience can feel daunting. Do you localize your product? Or, do you internationalize your product? And what does that even entail?为全球观众设计可能会令人生畏。 您是否将产品本地化&#xff1f; 还是您将…

springMVC_数据的处理过程

1、DispatcherServlet&#xff1a;作为前端控制器&#xff0c;负责分发客户的请求到 Controller 其在web.xml中的配置如下&#xff1a; <servlet><servlet-name>dispatcherServlert</servlet-name><servlet-class>org.springframework.web.servlet.Dis…

面试体验:Facebook 篇(转)

http://www.cnblogs.com/cathsfz/archive/2012/11/05/facebook-interview-experience.html 2012-11-05 08:20 by Cat Chen, 23266阅读, 121评论, 收藏, 编辑 Google、Microsoft 和 Yahoo 都是去年的事情了&#xff0c;接下来说说今年…

JavaScript 新增两个原始数据类型

大家好&#xff0c;我是若川。持续组织了6个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列JavaS…

axure低保真原型_如何在Google表格中创建低保真原型

axure低保真原型Google Sheets is a spreadsheet, just like Microsoft Excel.Google表格是一个电子表格&#xff0c;就像Microsoft Excel一样。 Most people associate it with calculating numbers. But Google Sheets is actually great for organizing your ideas, making…

Weblogic EJB 学习笔记(3)精

编辑实体bean的高级课程 1. 怎样开发主健类 ejb的主健类主要用做持久存储和ejb容器中的唯一标识符. 通常主健类的字段直接映射到数据库中的主健字段. 如果主健只是由单个实体bean字段组成.且其数据类型是基本的java类.如string,则bean作者不必开发自定义的主健类. 只需要在配置…

Lerna 运行流程剖析

大家好&#xff0c;我是若川。持续组织了6个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列Lerna…

手动创建线程池 效果会更好_创建更好的,可访问的焦点效果

手动创建线程池 效果会更好Most browsers has their own default, outline style for the :focus psuedo-class.大多数浏览器对于&#xff1a;focus psuedo-class具有其默认的轮廓样式。 Chrome’s default outline styleChrome浏览器的默认轮廓样式 This outline style is cr…

C++builder enum类型

C/C code #pragmaoption push -b-enumTThreadPriority { tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest, tpTimeCritical }; //这是字节型的.理论上说这是可能的最小整形.可以是1Byte, 2Bytes, 4Bytes...#pragmaoption pop#pragmaoption push -benumTThreadPriori…

chrome浏览器世界之窗浏览器的收藏夹在哪?

今天心血来潮&#xff0c;用一个查重软件删除重复文件&#xff0c;结果把chrome浏览器和世界之窗浏览器的收藏夹给删除了&#xff0c;导致我保存的好多网页都没有了&#xff0c;在浏览器本身和网上都没有找到这两个浏览器默认的收藏夹在哪个位置&#xff0c;只好用DiskGenius 把…

Vue3究竟好在哪里 等推荐

话不多说&#xff0c;这一次花了几小时精心为大家挑选了30余篇好文&#xff0c;供大家阅读学习&#xff0c;提升自己的技术视野以及扩展自己的知识储备。本文阅读技巧&#xff0c;先粗看标题&#xff0c;感兴趣可以都关注一波&#xff0c;一起共同进步。前端从进阶到入院框架原…

eazy ui 复选框单选_UI备忘单:单选按钮,复选框和其他选择器

eazy ui 复选框单选重点 (Top highlight)Pick me! Pick me! No, pick me! In today’s cheat sheet we will be looking at selectors and how they differ. Unlike most of my other cheat sheets, this will focus on two components (radio buttons and checkboxes) side by…

过滤词

<?xml version"1.0" encoding"GB2312"?>-<wordList> <word>,</word> <word>.</word> <word><</word> <word>></word> <word>?</word> <word>/</word> <…

VS2010 VC Project的default Include设置

http://blog.csdn.net/jeffchen/article/details/5491435 VS2010与以往的版本一个最大的不同是&#xff1a;VC Directory设置的位置和以前的版本不一样。VS2010之前&#xff0c;VC Directory的设置都是在IDE的Tools->Options中设置的&#xff1b;VS2010改为&#xff0c;分别…

初级中级高级_初级职位,(半)高级职位

初级中级高级As a recent hire at my new job, as expected, a lot of things seemed scary and overwhelming. The scariest part was not the unfamiliarity with certain tasks or certain tools, but in communicating with higher-level coworkers, managers and bosses. …

如何写好技术文章(看张鑫旭老师的直播总结

大家好&#xff0c;我是若川。持续组织了6个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列本文是…

Fact Table and Dimension Table In My Opinion

23转载于:https://www.cnblogs.com/answeryou/archive/2012/05/10/2495122.html

iOS 流媒体 基本使用 和方法注意

项目里面需要添加视频方法 我自定义 选用的是 avplayer 没选择 MediaPlayer 原因很简单 , avplayer 会更容易扩展 有篇博客 也很好地说明了 使用avplayer的优越性 blog.csdn.net/think12/article/details/8549438在iOS開發上&#xff0c;如果遇到需要播放影片&#xff0c;…