平衡树

平衡树就是一种可以在log的时间复杂度内完成数据的插入,删除,查找第k大,查询排名,查询前驱后继以及其他许多操作的数据结构。

Treap

treap是一种比较好写,常数比较小,可以实现平衡树基本操作的一种平衡树。treap的平衡是基于随机化。是将堆与二叉查找树结合起来所得到的数据结构。

treap在插入数时,给每个数赋了一个新的随机的值id。在以后的操作中,必须始终使得treap中的id构成一个堆的形态才可以。这样就达到了平衡的目的。

定义

  1. struct node {
  2. int ch[2],val,id,cnt,siz;
  3. }TR[N];

ch[0/1]分别表示左右儿子。

val是插入的数

id是赋给这个数的一个随机的值

cnt表示这个数字出现的次数

siz为在treap中以这个点为根的数字的个数

更新

  1. void up(int cur) {
  2. TR[cur].siz = TR[ls].siz + TR[rs].siz + TR[cur].cnt;
  3. }

就是维护一下siz

旋转

f表示将左(0)还是右(1)儿子旋转上来。

如图



加入我们现在要把2旋转到6这个位置,那么旋转之后6肯定成为了2的右儿子,那4去哪里呢。我们就把4变成6的左儿子,这样就完成了旋转。然后在维护一下siz就行了。

就成了这样



因为treap不存父亲,所以这里要取地址,把6换成2

  1. void rotate(int &cur,int f) {
  2. int son = TR[cur].ch[f];
  3. TR[cur].ch[f] = TR[son].ch[f ^ 1];
  4. TR[son].ch[f ^ 1] = cur;
  5. up(cur);
  6. cur = son;
  7. up(cur);
  8. }

插入

插入一个元素时我们只要按照与二叉查找树相同的方法,找到一个合适的位置插入即可。如果这个元素以前已经插入过了。那么只要把这个数的cnt++就行了。插入完成之后,还要维护id满足堆的形态这个条件。所以如果插入之后的儿子的id比当前节点的id小了,那么就将儿子旋转上来就行了。

  1. void insert(int &cur,int val) {
  2. if(!cur) {
  3. cur = ++tot;
  4. TR[cur].val = val;
  5. TR[cur].id = rand();
  6. TR[cur].cnt = TR[cur].siz = 1;
  7. return;
  8. }
  9. TR[cur].siz++;//!!
  10. if(TR[cur].val == val) { TR[cur].cnt++;return;}
  11. int d = val > TR[cur].val;
  12. insert(TR[cur].ch[d],val);
  13. if(TR[TR[cur].ch[d]].id < TR[cur].id) rotate(cur,d);
  14. }

删除

首先找到要删除的节点,根据这个节点儿子的个数可以分为两种情况。

情况1:这个节点有1个或者0个儿子。那么直接将这个节点变为这个节点的儿子(没有就是0)就行了

情况2:这个节点有2个儿子。那么不断的往下旋转这个节点,知道满足情况1。在旋转的时候应该注意,因为要满足堆这个条件。所以应该将儿子中id较小的那个旋转上来。

  1. void del(int &cur,int val) {
  2. if(!cur) return;
  3. if(val == TR[cur].val) {
  4. if(TR[cur].cnt > 1) {TR[cur].cnt--;TR[cur].siz--; return;}
  5. if(!ls || !rs) {cur = ls + rs;return;}
  6. int d = TR[rs].id < TR[ls].id;
  7. rotate(cur,d);
  8. del(cur,val);
  9. }
  10. else TR[cur].siz--,del(TR[cur].ch[val > TR[cur].val],val);
  11. }

查找排名

这个就真的和二叉搜索树一样了。如果要找的那个数字比当前节点大。那么就将排名加上左子树大小,然后搜右子树,否则搜左子树。

  1. int Rank(int cur,int val) {
  2. if(!cur) return 0;
  3. if(val == TR[cur].val) return TR[ls].siz + 1;
  4. if(val < TR[cur].val) return Rank(ls,val);
  5. return Rank(rs,val) + TR[ls].siz + TR[cur].cnt;
  6. }

查找第k大(排名为k的元素)

和查找排名差不多。只要不断的记录下要查找当前子树中的第几大。如果比左子树大小加上根节点大小还大,那么就减去左子树大小和根大小,并查找右子树,否则查找左子树

  1. int kth(int cur,int now) {
  2. while(1) {
  3. if(TR[ls].siz >= now) cur = ls;
  4. else if(TR[ls].siz + TR[cur].cnt < now) now -=TR[ls].siz + TR[cur].cnt,cur = rs;
  5. else return TR[cur].val;
  6. }
  7. }

前驱

还是从根往下搜索,如果要找的数比当前根节点要大,那么就搜索右子树,并将搜到的答案与当前根取max,否则就搜索左子树

  1. int pred(int cur,int val) {
  2. if(!cur) return -INF;
  3. if(val <= TR[cur].val) return pred(ls,val);//!!!
  4. return max(pred(rs,val),TR[cur].val);
  5. }

后继

跟前驱同理

  1. int nex(int cur,int val) {
  2. if(!cur) return INF;
  3. if(val >= TR[cur].val) return nex(rs,val);//!!!
  4. return min(nex(ls,val),TR[cur].val);
  5. }

一言

迷途经累劫,悟则刹那间。 ——六祖坛经

[Treap][学习笔记]的更多相关文章

  1. 左偏树 / 非旋转treap学习笔记

    背景 非旋转treap真的好久没有用过了... 左偏树由于之前学的时候没有写学习笔记, 学得也并不牢固. 所以打算写这么一篇学习笔记, 讲讲左偏树和非旋转treap. 左偏树 定义 左偏树(Lefti ...

  2. fhq treap 学习笔记

    序 今天心血来潮,来学习一下fhq treap(其实原因是本校有个OIer名叫fh,当然不是我) 简介 fhq treap 学名好像是"非旋转式treap及可持久化"...听上去怪 ...

  3. Treap + 无旋转Treap 学习笔记

    普通的Treap模板 今天自己实现成功 /* * @Author: chenkexing * @Date: 2019-08-02 20:30:39 * @Last Modified by: chenk ...

  4. treap学习笔记

    treap是个很神奇的数据结构. 给你一个问题,你可以解决它吗? 这个问题需要treap这个数据结构. 众所周知,二叉查找树的查找效率低的原因是不平衡,而我们又不希望用各种奇奇怪怪的旋转来使它平衡,那 ...

  5. Treap-平衡树学习笔记

    平衡树-Treap学习笔记 最近刚学了Treap 发现这种数据结构真的是--妙啊妙啊~~ 咳咳.... 所以发一发博客,也是为了加深蒟蒻自己的理解 顺便帮助一下各位小伙伴们 切入正题 Treap的结构 ...

  6. 平衡树学习笔记(2)-------Treap

    Treap 上一篇:平衡树学习笔记(1)-------简介 Treap是一个玄学的平衡树 为什么说它玄学呢? 还记得上一节说过每个平衡树都有自己的平衡方式吗? 没错,它平衡的方式是......rand ...

  7. FHQ treap学习(复习)笔记

    .....好吧....最后一篇学习笔记的flag它倒了..... 好吧,这篇笔记也鸽了好久好久了... 比赛前刷模板,才想着还是补个坑吧... FHQ,这个神仙(范浩强大佬),发明了这个神仙的数据结构 ...

  8. 「学习笔记」Treap

    「学习笔记」Treap 前言 什么是 Treap ? 二叉搜索树 (Binary Search Tree/Binary Sort Tree/BST) 基础定义 查找元素 插入元素 删除元素 查找后继 ...

  9. [学习笔记]平衡树(Splay)——旋转的灵魂舞蹈家

    1.简介 首先要知道什么是二叉查找树. 这是一棵二叉树,每个节点最多有一个左儿子,一个右儿子. 它能支持查找功能. 具体来说,每个儿子有一个权值,保证一个节点的左儿子权值小于这个节点,右儿子权值大于这 ...

随机推荐

  1. Ubuntu16.04下OpenCV调用笔记本摄像头

    1,新建一个test.cpp文件,插入下列代码,保存 #include<opencv2/opencv.hpp> #include<iostream> using namespa ...

  2. Eclipse安装hibernate插件

    进入hibernate官网下载 http://tools.jboss.org/downloads/ 选择合适版本 下载完成后在eclipse->help->intall new softe ...

  3. Spring MVC(二)基于标注的MVC

    1.基于标注的Spring MVC 1.1 建立一个项目导入jar包(ioc aop mvc) 拷贝容器对应的配置文件到src下 在WEB-INF建立一个login.jsp 1.2 在web.xml ...

  4. Web后端 JAVA学习之路

    1.Java分类 Java按应用来分,可以分为J2ME(手机版),J2SE(标准版),J2EE(企业版)三部分. ・J2ME:已经被安卓开发取代. ・J2SE:Java的核心类,其中包括桌面应用,但一 ...

  5. 重建程序员能力(2)-如何使asp.net mvc应用增加js和其他功能

    1. 在Visual Studio的解决方案资源管理器,找到项目右键展开右键菜单后选择 管理NuGet程序包. 2.在打开的页面中,可以按需要选择Jquery.BootStrap等页面展现框架. 有工 ...

  6. Winserver-默认以管理员运行程序

    打开secpol.msc 打开本地安全策略找到安全设置--本地策略--安全选项用户账户控制:以管理员批准模式运行所有管理员---改为禁用保存设置重启电脑

  7. 【原】无脑操作:IDEA热部署设置

    热部署的概念:在应用正在运行的时候升级软件,却不需要重新启动应用.对于Java应用程序来说,热部署就是在运行时更新Java类文件. 注意:经过试验,IDEA 2017可以使用热部署,IDEA 14不行 ...

  8. windowsserver 2019系统安装教程

    windowsserver2019和windowsserver2016一样也分两个版本标准版和数据中心版. 1.插入系统光盘 2.选择安装版本一般选择带桌面体验的,要不安装成功后没有桌面. 3.设置分 ...

  9. JVM内存结构简单认知

    关于JVM的面试传送门:https://blog.csdn.net/shengmingqijiquan/article/details/77508471 JVM内存结构主要划分为:堆,jvm栈,本地方 ...

  10. golang web实战之二(iris)

    之前写了一篇为:golang web实战之一(beego,mvc postgresql) 听说iris更好: 1.  iris hello world package main import &quo ...