Treap
I will translate this blog to English ASAP.
##前置芝士
熟练掌握二叉查找(排序)树的插入、删除、求排名、求某一排名的数、求前驱、求后继等操作。
#引言 二叉查找树看似可以在
此时,在此图上操作的时间复杂度仍为
#正文 Treap又名树堆,是一种利用随机性来维持二叉查找树的平衡形态的树(相较于Splay,方便且暴力许多)。 学习Treap,首先需要了解Treap的特色旋转操作(与Splay的旋转有一定差别)。旋转操作在Treap中主要用于在不破坏二叉查找树的性质(左子树比根小,右子树比根大)的情况下,对元素的位置进行挪动。根据所需旋转的节点属于其父亲节点的左子树和右子树,可分为左旋和右旋。 | ||
---|---|---|
###插入节点
Treap的插入操作与普通的二叉查找树如出一辙,但是为了保持平衡,每个节点会有一个随机值来保证图的形态的随机性。
###操作步骤 #####1、从根节点开始递归;
#####2、如果当前节点的值等于需插入的值,则将该节点的数值数量和该节点的子树的节点数+1;
#####3、如果当前节点的值大于需插入的值,则在当前节点的左儿子中继续2、3两步;如果当前节点的值小于需插入的值,则在当前节点的右儿子中继续2、3两步。操作完成后,若子节点的随机值大于当前节点的随机值,则将当前节点向下旋转;
#####4、如果当前节点为空节点,则在当前节点中建立新的节点,并赋予新节点一个随机值;
####代码
|
###删除节点 删除操作和插入节点的区别在于,需要分类讨论需删除的节点的状态(左儿子存在与否、右儿子存在与否)。
#####情况一:左儿子右儿子都不存在 因为叶子节点的存在不会影响整树的平衡,所以此时可以直接删除该节点; #####情况二:左儿子存在、右儿子不存在 若直接删除节点,有可能影响树的平衡性,所以将当前节点向左儿子旋转; #####情况三:左儿子不存在,右儿子存在 与情况二大同小异,差别是要将当前节点向右儿子旋转; #####情况四:左儿子存在,右儿子存在 此时需要选择旋转左旋还是右旋。显然,若进行左/右旋,则左/右儿子会更替当前节点的位置。故为了维持树的随机性,需要将左儿子和右儿子中随机值大的点向上旋转;
点的遍历操作与插入节点的遍历如出一辙,此处不再赘述。 ####代码
1 | void del (int &p, int x) { |
###遍历操作 ###情况一:若当前节点的值等于查找的树,则返回当前节点的左子树的数量+1; ###情况二:若当前节点的值小于需查找的值,则返回 需查找的值在右子树的排名+当前节点的左子树的节点数+当前节点的数量; ###情况三:若当前节点的值大于需查找的值,则返回 需查找的值在左子树的排名;
####代码
1 | int ranks (int p, int x) { |
####代码
1 | int find (int p, int x) { |
####代码
1 | int pre (int p, int x) { |
1 | #include <bits/stdc++.h> |
- Title: Treap
- Author: Harry Huang (aka Wenyuan Huang, 黄问远)
- Created at : 2024-11-07 01:35:27
- Updated at : 2024-11-27 21:53:28
- Link: https://whuang369.com/blog/2024/11/07/CS/ICPC/Treap/
- License: This work is licensed under CC BY-NC-SA 4.0.
Comments