当前位置: 首页 > news >正文

平衡树

二叉查找树

在不考虑复杂度的情况下,是一种严格强于线段树的结构。

其结构为左子树小于当前节点,右子树大于当前节点,所以中序遍历就是按全部结点权值大小从小到大遍历。

二叉查找树可支持新增节点,查询一个节点的排名,查询一个排名对应的节点。如果点维护的是权值和,那么可以实现单点修改,区间查询。

但假如每次都插入最小值,树会退化成一条链,每次查找的时间复杂度也就退化为 \(O(n)\),所以我们需要平衡这棵二叉查找树,由此引入平衡树。

替罪羊树

替罪羊树平衡二叉查找树的方法是当整棵树失衡的时候重构。那何时整棵树才算失衡呢,如下图所示:

graph

发现右子树大小占了整棵树大小的大部分,那么我们就可以设置一个平衡权值 \(\alpha\),当左子树或右子树的大小大于 \(\alpha \times siz_u\) 的时候,整棵树就是失衡的。这是其中一种失衡情况,另外一种会在后文出现,而 \(\alpha\) 的取值在重构结束会提到。

现在已知一棵子树失衡了,那么如何重构这棵子树且使其满足二叉搜索树的性质呢?我们考虑对这棵子树进行中序遍历,得到的序列必然是权值从小到大排序的序列,此时考虑重构这棵子树的结构。由于需要尽量让该子树平衡,所以每次可以选取该序列中点,当作新的根,然后分别对左子树和右子树进行递归操作,这样既保证了二叉搜索树的性质,又能使树高尽量的小。

中序遍历+重构:

void unfold(int x){if(!x) return;unfold(ls[x]);if(sum_id[x]) rt[++cnt_rt]=x;unfold(rs[x]);return;
}//中序遍历将子树变成序列 #define mid (l+r>>1)void pushup(int x){siz1[x]=siz1[ls[x]]+siz1[rs[x]],//可重集大小(减去了删除的点个数)siz2[x]=siz2[ls[x]]+siz2[rs[x]];//可重集大小(未减去删除的点个数) 
}//向上合并int rebuild(int l,int r){if(l>r) return 0;if(l==r) return rt[l];ls[rt[mid]]=rebuild(l,mid-1);rs[rt[mid]]=rebuild(mid+1,r);pushup(rt[mid]);return rt[mid]; 
}//重构子树,利用类似线段树的方法void bel(int x){cnt_rt=0;unfold(x);rebuild(1,cnt_rt);}//综合重构操作  

这样的单次重构的时间复杂度是 \(size(x)\) 的,那么考虑 \(\alpha\) 的取值,首先其肯定要大于 \(0.5\),因为左右子树大小的最大值肯定大于等于整棵子树大小的 \(0.5\)。其次其不能很小,这样会导致重构次数增加,所以考虑 \(0.7 \sim 1\)。最后其不能太大,因为当一棵树不失衡的情况下,树高最高为 \(\log_{\frac{1}{\alpha}} n\),当 \(\alpha\) 太大的时候,整棵树的树高会很大,就会导致整棵树每次查找的时间复杂度爆炸。所以一般来说,\(\alpha\)\(0.7 \sim 0.8\) 之间最好。

那么基础操作基本结束,现在就需要解决题目中的问题了,可以参考这个题目要求的问题。

先看操作 \(2\) 也就是删除操作,对于删除操作,我们肯定是找到该点,使其的总副本数减去 \(1\),然后直接返回。但是发现如果总副本数为 \(0\) 的话该点就不复存在了,留在原地可能会失衡并影响失衡的判断,所以另外一个失衡的判定由此而出,当一棵子树内删除的点大于总子树大小乘 \(1- \alpha\) 时,该子树就是失衡的,所以综上,判定失衡代码即为:

bool check(int x){return fb[x]&&max(tr2[x]*alp<max(tr2[ls[x]],tr2[rs[x]]))||tr1[x]>alp*tr2[x]; 
}//fb_x 为 x 节点的副本数 

现在已经万事具备了,让我们具体解决操作。

  • 操作 \(1\),插入一个数 \(x\)。根据二叉查找树的性质,我们可以很快的找到 \(x\) 应在的位置,如果 \(x\) 以前存在过,那就直接将副本数增加;否则就新开一个节点。
void insert(int &rt,int x){if(!rt){rt=++cnt,fb[rt]=1,tr1[rt]=1,tr2[rt]=1;return;}if(x==val[rt]){fb[rt]++,tr1[rt]++,tr2[rt]++;return;}if(x<val[rt]) insert(ls[rt],x);else insert(rs[rt],x);pushup(rt);
} 
  • 操作 \(2\)
http://www.vanclimg.com/news/2645.html

相关文章:

  • Windows 平台的路由表配置
  • 怎么使用德布鲁因序列编码三色激光条纹?
  • BSC链验证者更新机制深度解析:Epoch、Snapshot与实时控制 - 若
  • Iron Software:助力.NET开发者轻松实现文档和图像处理功能
  • 通过对二维地震模拟中有限差分法进行模拟,实现地震合成记录
  • Three.js 的第一个工程-添加文本
  • Random
  • SLF4J Logback Log4j, Log4j2
  • 理解非线性市值因子NLSIZE/MIDCAP
  • 杜教筛
  • Java核心类——3.StringJoiner
  • Messager 详解:WPF 中的消息传递与数据绑定入门指南
  • Fastmcp 案例五(Cherry Studio调式 ,结合案例四)
  • Unity加载资源的方式
  • IMA-Appraisal HASH fix mode和enforce mode的解释
  • C# Avalonia 06 - Controls- MediaElement
  • 学习笔记《莫比乌斯反演》
  • 惯性导航+DVL的组合导航算法
  • CVE-2016-5385 CGI 应用环境变量注入漏洞 (复现)
  • spring和Mybatis的逆向工程
  • 解决keil使用UTF-8乱码问题,兼容UTF-8编码,但keil显示不乱码的解决方案
  • 解决MySQL删除/var/lib/mysql下的所有文件后无法启动的问题
  • godot 二维报表库
  • EG800KCN移远4G模块wifiscan辅助定位
  • 基于小波分析和TV非凸模型的图像去模糊去噪算法
  • Ubuntu24.04体验Qwen3-Coder
  • 实验室检测仪器数据采集监控联网
  • Adobe InDesign 2025(id2025)安装教程-附mac+win安装包
  • IC验证常见88道
  • 【JPCS出版】第六届先进材料与智能制造国际学术会议(ICAMIM 2025)