Treap树结构

树结构与动态操作算法的深入解析 本文将深入探讨树结构及其上的动态操作,包括动态树的构建、树上操作和平衡二叉树(如Treap)的原理与应用。通过具体问题的分析,如区间更新、查询第2大权值等,我们将理解树上动态操作的算法设计和实现过程。 阅读详情

        Treap,是有一个随机附加域满足堆的性质的二叉搜索树,其结构相当于以随机数据插入的二叉搜索树。其基本操作的期望时间复杂度为O(logn)。相对于其他的平衡二叉搜索树,Treap的特点是实现简单,且能基本实现随机平衡的结构。

        Treap=Tree+Heap。Treap本身是一棵二叉搜索树,它的左子树和右子树也分别是一个Treap,和一般的二叉搜索树不同的是,Treap纪录一个额外的数据,就是优先级。Treap在以关键码构成二叉搜索树的同时,还满足堆的性质。Treap维护堆性质的方法用到了旋转,只需要两种旋转,编程复杂度比Splay要小一些。

插入

        给节点随机分配一个优先级,先和二叉搜索树的插入一样,先把要插入的点插入到一个叶子上,然后跟维护堆一样,如果当前节点的优先级比根大就旋转,如果当前节点是根的左儿子就右旋如果当前节点是根的右儿子就左旋。

由于旋转是O(1)的,最多进行h次(h是树的高度),插入的复杂度是O(h)的,在期望情况下h=O(logn),所以它的期望复杂度是O(logn)。

删除

        因为Treap满足堆性质,所以只需要把要删除的节点旋转到叶节点上,然后直接删除就可以了。具体的方法就是每次找到优先级最大的儿子,向与其相反的方向旋转,直到那个节点被旋转到了叶节点,然后直接删除。

删除最多进行O(h)次旋转,期望复杂度是O(logn)。

查询

        和一般的二叉搜索树一样,但是由于Treap的随机化结构,Treap中查找的期望复杂度是O(logn)。

代码(一种递归实现):

#include <iostream>
#include <iomanip>
#include <queue>
#include <cstdlib>
using namespace std;

typedef struct TreapNode * Treap;
typedef struct TreapNode
{
	int data;
	int priority;
	Treap lchild,rchild;
} TreapNode; 
#define Infinity 0x7FFFFFFF
Treap NullNode = NULL;

Treap Initialize(void)
{
	if (NullNode == NULL) 
	{
		NullNode = new TreapNode;
		NullNode->priority = Infinity;
		NullNode->lchild = NullNode->rchild = NullNode; 	
	}
	return NullNode;
}

Treap SingleRotateWithLeft(Treap x)
{
	Treap y = x->lchild;
	x->lchild = y->rchild;
	y->rchild = x;
	return y;
}
Treap SingleRotateWithRight(Treap x)
{
	Treap y = x->rchild;
	x->rchild = y->lchild;
	y->lchild = x;
	return y;
}
Treap insert(int key, Treap T)
{
	if (T == NullNode) {
		/* create and return an one-node tree */
		T = new TreapNode;
		T->data = key;
		T->priority = rand();
		T->lchild = T->rchild = NullNode; 
	}
	else
	{
		if (key < T->data) {
			T->lchild = insert(key, T->lchild);
			if (T->lchild->priority < T->priority) {
				T = SingleRotateWithLeft(T);
			}
		}
		else if (key > T->data) {
			T->rchild = insert(key,T->rchild);
			if (T->rchild->priority < T->priority) {
				T = SingleRotateWithRight(T);
			}
		}
		
	}
	return T;
}

Treap remove(int key, Treap T)
{
	if (T != NullNode) 
	{
		if (key < T->data) {
			T->lchild = remove(key,T->lchild);		
		}	
		else if (key > T->data) {
			T->rchild = remove(key,T->rchild); 
		}
		else {
			/*match found*/
			if (T->lchild->priority < T->rchild->priority)
				T = SingleRotateWithLeft(T);
			else 
				T = SingleRotateWithRight(T);
				
			if (T != NullNode) /* continue go down*/
				T = remove(key,T);
			else
			{
				/* at a leaf*/
				delete (T->lchild);
				T->lchild = NullNode;
			} 
		}
	}
	return T;
}

/*------------------about tree display -----------------------------------------*/
inline int max(int a,int b)
{
	return a>b?a:b;
}
int Height(Treap T)
{
	if (T == NullNode)
		return 0;
	else
		return 1 + max(Height(T->lchild), Height(T->rchild));
}
void MakeMat(Treap T,int root_x,int root_y,int step,int **m)
{
	int lChildPos,rChildPos;
	lChildPos = root_x - step;
	rChildPos = root_x + step;
	if (T == NullNode) 
		return;
	else
	{
		m[root_y][root_x] = 1;
		MakeMat(T->lchild,lChildPos,root_y+1,step>>1,m);
		MakeMat(T->rchild,rChildPos,root_y+1,step>>1,m);
	}
}

void TreapDisplay(Treap T)
{
	if(T == NullNode)
		return;
	/* init placehold flags m[h][len] */
	int h = Height(T);
	int len = (1<<h) - 1;
	int row = h; 
	int **m = new int*[row];
	for(int i= 0;i<row;i++){
		m[i] = new int[len];
		memset(m[i],0,len*sizeof(int));	
	}
	/* get level order traversal sequence */
	vector<Treap> v;
	queue<Treap> q;
	queue<Treap> qt;
	q.push(T);
	Treap pt;
	while(!q.empty())
	{
		pt = q.front();
		if (pt->lchild != NullNode)
			q.push(pt->lchild);
		if(pt->rchild != NullNode)
			q.push(pt->rchild);
		v.push_back(pt);		
		q.pop();
	}
	/* generate output matrix  plus '/' and '\\' m[2*h-1][len] */
	MakeMat(T,len>>1,0,len+1>>2,m);
	/* generate output */
	int cnt = 0;
	int width = 1;
	for(int i = 0; i < row; i++)
	{
		for(int j = 0; j < len; j++)
		{
			if(m[i][j])
			{
//				if (i & 1) 
//					cout<<setw(width)<<char(m[i][j]);
//				else
//					cout<<setw(width)<<char(m[i][j]);
//					cout<<setw(width)<<m[i][j];
				cout<<(v[cnt])->data;
				cnt++;
			}
			else
				cout<<setw(width)<<' ';		
		}
		cout<<endl;
	}
	
}

/*-------------- I am a cut-----------------------------------------------------*/
int main()
{
	NullNode = Initialize();
	Treap T = NullNode;
	int i;
	for (i = 1; i <= 7 ; i++) 
	{
		cout<<"Key = "<<i<<" inserting :"<<endl;
		T = insert(i,T);
		TreapDisplay(T);
		cout<<"------------------------------------------"
		"--------------------------"<<endl; 
	}
	for( i = 1;i <= 7; i++)
	{
		cout<<"Key = "<<i<<" deleting :"<<endl;
		T = remove(i,T);
		TreapDisplay(T);
		cout<<"------------------------------------------"
		"--------------------------"<<endl; 
	}
	
}

代码输出:

Key = 1 inserting :
1
--------------------------------------------------------------------
Key = 2 inserting :
 1 
  2
--------------------------------------------------------------------
Key = 3 inserting :
   1   
     3 
    2  
--------------------------------------------------------------------
Key = 4 inserting :
   1   
     3 
    2 4
--------------------------------------------------------------------
Key = 5 inserting :
       1       
           3   
         2   5 
            4  
--------------------------------------------------------------------
Key = 6 inserting :
               1               
                       3       
                   2       6   
                         5     
                        4      
--------------------------------------------------------------------
Key = 7 inserting :
                               1                               
                                               3               
                                       2               7       
                                                   6           
                                                 5             
                                                4              
--------------------------------------------------------------------
Key = 1 deleting :
               3               
       2               7       
                   6           
                 5             
                4              
--------------------------------------------------------------------
Key = 2 deleting :
               3               
                       7       
                   6           
                 5             
                4              
--------------------------------------------------------------------
Key = 3 deleting :
       7       
   6           
 5             
4              
--------------------------------------------------------------------
Key = 4 deleting :
   7   
 6     
5      
--------------------------------------------------------------------
Key = 5 deleting :
 7 
6  
--------------------------------------------------------------------
Key = 6 deleting :
7
--------------------------------------------------------------------
Key = 7 deleting :
--------------------------------------------------------------------

REF:

1,http://zh.wikipedia.org/wiki/Treap

2,数据结构与算法分析-C语言描述 

树结构在数据存储与检索中的应用 本文将探讨树结构如何应用于数据存储和检索,特别关注平衡树的原理、多路树和B树在外部搜索中的优势。我们将深入分析Jean Vuillemin引入的Cartesian trees、treap数据结构的特性以及Bayer和McCreight提出的B树概念,理解其在实际应用中的重要性。 阅读详情

相关推荐

一周涨十万星,GitHub 爆火的 REA 逆向工程到底是什么?

REA 这波热度里,我一直没太想明白的是它为什么火在 AI 圈而不是安全圈。同类的 MCP 工具早就在了,技术上也谈不上新,真正变的只有一件事:门槛。门槛一降,参与的人就从"会逆向的工程师"变成了"会打字的任何人"。这大概也是争议的根源。护城河这件事,多数报道的共识是它从"你看不到我的代码"挪到了"你拿不走我的服务能力和业务理解"。这话对不对,现在没人拿得出证据,只能等下一批真实案例。哪天有人拿 REA 把某个还在卖钱的闭源软件啃出可维护的工程,那个答案才算落地。

优快云zhizunbao的博客 1190

快乐的爆10周末(虽然已经过去了许久)

书接上回,终于还是把那道题改出来了,于是时隔多年我来把那天的题来写一写。 这一道题写了这么久,果然还是太逊了。 书归正传,还是先来看一下题: T1 匹配 Match 题目描述 给定一个仅含小写字母的字符串S[0…n-1],对于一个询问(p, q, len),我们想知道它的两个子串S[p…p+len-1]、S[q…q+len-1] 是否相同。更多地,我们希望在对串S 完成一些操作之后还能高效地得到这个结果。我们具体要维护以下几个操作(其中L 为操作之前的串长): ●1 pc:在下标p之前插入一个小写字母c

YunYuanWang的博客 337

用Python实现单层感知器:5分钟搞定逻辑与/或/异或分类(附避坑指南)

本文通过Python代码实战,详细讲解了单层感知器的核心原理与实现步骤,5分钟内即可完成逻辑与、或运算的分类任务。文章深入剖析了单层感知器的能力边界,解释了其无法解决异或(XOR)等线性不可分问题的根本原因,并提供了学习率设置、权重初始化等关键避坑指南,帮助初学者直观理解神经网络的基础。

ttt77的博客 1084

treap基本操作

利用rand保持堆的特性 const int N=; int ls[N],rs[N],v[N],p[N],cnt[N],siz[N]; // 权值 优先级 inline void update(int &k){ siz[k]=siz[ls[k]]+siz[rs[k]];} inline void zig(int &k){//t...

weixin_30846599的博客 147

Sigrity Power Tree如何进行直流压降仿真分析操作指导

Sigrity Power Tree模式可以用于前仿真,在没有layout文件的情况下对电源进行直流压降仿真分析,用于评估原理图设计以及器件选型是否合理。Model:设置为Equal Current,设置为等电源模型,意思该负载每个电源pin都是等电流的。Current:设置每个负载的电流,U30为3A,U3-U6各为1A。Nominal Current:设置能够承载的最大电流,设置为10A。Upper/ Lower Tol:设置为压降范围为5%Output Current:设置输出电流为10A。

weixin_54787054的博客 732

基于 YOLOv26 的遥感图像目标检测系统:从原理到模型

本文介绍了基于YOLOv26的遥感图像目标检测系统。YOLOv26凭借端到端设计、轻量化架构和小目标优化能力,有效解决了遥感图像中多尺度目标、复杂背景、小目标检测等挑战。系统采用CSPDarknet骨干网络和FPN+PAN特征融合模块,通过MuSGD优化器和改进损失函数提升训练效果。文章详细阐述了数据预处理、模型训练流程和优化技巧,包括Tile推理和混合精度训练。系统支持多种部署方式,在CPU上推理速度提升43%,能实现高精度、实时性的遥感目标检测,适用于城市规划、农业监测等场景。

一键难忘的博客 568

查找——图文翔解Treap(树堆)

Treap=Tree+Heap。Treap本身是一棵二叉搜索树,它的左子树和右子树也分别是一个Treap,和一般的二叉搜索树不同的是,Treap纪录一个额外的数据,就是优先级。Treap在以关键码构成二叉搜索树的同时,还满足堆的性质。这些优先级是是在结点插入时,随机赋予的,Treap根据这些优先级满足堆的性质。这样的话,Treap是有一个随机附加域满足堆的性质的二叉搜索树,其结构相当于以随机数据插入的二叉搜索树。其基本操作的期望时间复杂度为O(logn)。相对于其他的平衡二叉搜索树,Treap的特点是实现简

菜鸟的自留地-mooyang 2万+

MATLAB基础应用精讲-【深度强化学习】SAC(Soft Actor-Critic)算法(附MATLAB和python代码实现)

Actor 网络:用于选择动作。Critic 1 和 Critic 2 网络:用于估计 Q 值。Target Critic 1 和 Target Critic 2:与 Critic 网络架构相同,用于生成更稳定的目标 Q 值。,即在保证探索的情况下选择高价值动作。软更新目标 Q 网络参数,使得目标网络参数缓慢向当前网络靠近,避免振荡。

qq_36130719的博客 454

Treap 基本操作

treap = tree + heap 写博原因: 在我学treap的时候网上的很多博客给了我很大的误解, 也有可能是我自己功底薄弱的原因, 网上很多很不错的博文都直接说Treap是平衡树, 由于我自以为平衡树就得满足节点左右孩子高度只差 终于才知道, 大家所说的平衡树其实分两种 1. 一种是绝对的平衡, 满足高度差 2. 而另一种却是期望平衡树, 也就是说通过计算, 数学期望

星空下的密码 2322

【Bug已解决】Codex CLI 报错 You‘ve hit your usage limit 解决方案

Codex CLI 密集使用时触发 You've hit your usage limit 限流报错,本质是订阅套餐额度机制在正常发挥作用。文中给出等待滚动重置、拆分大任务、主动管理上下文、升级套餐、团队排队机制等完整解决方案。

博客 1万+

深度解析 Android 开发工程师岗位:技术栈、职责与面试全攻略

本文深度剖析Android开发工程师职位要求,从核心技术栈到面试准备进行全面解读。关键点包括:1)掌握Kotlin语言特性和Jetpack组件;2)具备UI开发、性能优化和逆向分析能力;3)理解MVVM架构和Room数据库;4)熟悉常用工具链和开发流程。文章提供了详细的面试题库及解析,涵盖基础概念、UI优化、架构设计等方向,并给出职业发展建议:夯实基础、拓展技术广度、培养工程素养。旨在帮助开发者系统性地准备Android岗位求职,把握移动开发领域的技术趋势。

郑伟强dev的专栏 173

史上最强图解Treap总结, 不是浅谈!

大家都很强, 可与之共勉。Treap = Tree + Heap. 树堆,在数据结构中也称Treap,是指有一个随机附加域满足堆的性质的二叉搜索树,其结构相当于以随机数据插入的二叉搜索树。其基本操作的期望时间复杂度为O(logn)。相对于其他的平衡二叉搜索树,Treap的特点是实现简单,且能基本实现随机平衡的结构。Treap 维护堆的性质的方法只用到了左旋和右旋, 编程复杂度比Splay小一点,

Lazer2001 1万+

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

树结构03—— Treap树

我们知道,二叉查找树相对来说比较容易形成最坏的链表情况,所以前辈们想尽了各种优化策略,包括AVL,红黑,以及今天 要讲的Treap树。        Treap树算是一种简单的优化策略,这名字大家也能猜到,树和堆的合体,其实原理比较简单,在树中维护一个"优先级“,”优先级“ 采用随机数的方法,但是”优先级“必须满足根堆的性质,当然是“大根堆”或者“小根堆”都无所谓,比如下面的一棵树:

Jason的专栏 236

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

树和树结构(2) : Treap树

测试题目来自 http://codevs.cn/problem/1164/ 部分内容来自网络 想要了解treap树,你先要知道什么是二叉搜索树。二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树:

OIljt12138的博客 845

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

6天通吃树结构—— 第三天 Treap树

原文:6天通吃树结构—— 第三天 Treap树 我们知道,二叉查找树相对来说比较容易形成最坏的链表情况,所以前辈们想尽了各种优化策略,包括AVL,红黑,以及今天 要讲的Treap树。 Treap树算是一种简单的优化策略,这名字大家也能猜到,树和堆的合体,其实原理比较简单,在树中维护一个"优先级“,”优先级“ 采用...

weixin_33743880的博客 84

【二叉平衡搜索树】Treap

我既是二叉搜索树又是堆。 treap:Java实现

博客网站地址: https://arsenova.xyz 我会将优快云上的博客重修一部分迁移到网站上。 文章会做同步更新,但我不会在这个糟糕的平台多待1秒。下面是我要说的话,save your time. keep going 958

【Treap】[BZOJ 3224]Tyvj 1728 普通平衡树

平衡树的入门题目,也可以用Treap来实现,我觉得Treap的核心就是那个rand()了用来保证树不退化成链,同时还是有平衡树的特性。。总体来说我觉得比较好些,而且比较快 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #i...

weixin_30598225的博客 82

无旋Treap——FHQ-Treap详解

FHQ-treap——无旋treap 前置知识: 二叉排序树 treap 了解什么是函数式编程 引入 “平衡树好烦啊,转来转去的,而且treap遇到区间序列问题就gg。” “有一种不用旋转的treap,叫FHQ-treap,可以解决区间序列问题。” 正文 约定 我们做出以下约定: int ch[MAXN][3];//0 左孩子,1右孩子 int val[MAXN];//每个点的权值 int rnd[MAXN];//每个点的随机权值 int size[MAXN];//以每个点为根的树的大小

Andysun06的博客 937

可持久化treap

平衡树是一个有用的结构,但是常用的splay等由于均摊复杂度和旋转操作,无法方便的可持久化。 这时候跳出一个treap,他可以可持久化! treap是一种笛卡尔树,有两个值:位置与权。这样构建出来的treap满足两个性质:1、左儿子位置小于当前节点小于右儿子,2、儿子的权值小于父亲。容易猜想,若权值随机,则树高是O(logn)。 使用类似二叉堆的旋转操作可以很方便的维护treap,但是还有一

miaom的博客 861
上一篇: AA树—简单的红黑树
下一篇: 大小端存储复习题
Scandinavians
博客等级 码龄19年 36粉丝 121原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值