斜堆(skew heap)
结构定义
斜堆(skew heap)也叫自适应堆(self-adjusting heap),它是左倾堆的一个变种。通常用来实现优先队列,支持插入,删除,合并操作,并且均摊复杂度都为。
斜堆在结构上没什么特殊要求,只需要是一颗二叉树,并且结点满足堆序即可。所谓堆序就是父结点的值小于等于儿子结点的值(最小堆),兄弟结点之间的大小没有约束。
操作定义
合并
斜堆的合并操作步骤如下:
- 如果一个空斜堆与一个非空斜堆合并,返回非空斜堆。
- 如果两个斜堆都非空,那么比较两个根结点,将较小的根结点的右孩子对应的子堆和另一个堆去合并,合并得到的新子堆的根结点作为新的右孩子。
- 将当前根结点的左右孩子互换位置。
最后一步很关键,简单地想一下,对于一个结点来说,合并的数据总是交替地插入自己的左边和右边,那么高度是不是就可以控制住了呢。
插入
插入一个结点就相当于合并只有一个结点的斜堆。
删除
移除一个结点,然后合并其左右子堆,用新堆的根结点替代自己即可。
复杂度分析
这里分析合并操作即可。下面将说明合并操作的均摊复杂度就是。
这里采用均摊分析来计算n次操作中,平均一次操作的均摊代价,首先需要定义一些概念:
- 假设一共要进行n次合并,但最终合并得到的斜堆最多包含n个结点,也就是最多有n个元素。
- 定义重结点(heavy)为右子堆结点数大于左子堆结点数的结点,否则为轻结点。
- 定义右路径为一直往右走的路径。
- 定义势能 为第i次合并后,重结点的个数之和。显然初始势能,最终势能。最终势能减初始势能范围也在,最后计算的时候让它加上一个n保持大于0就行了。
考虑第i次合并过程,比如堆a,和堆b。它们右路径上轻、重点个数分别为,和和。那么这次合并的实际开销为
本次合并之后,在右路径上,一个重结点右儿子本来就比左儿子重,合并又发生在右儿子,交换后左儿子大于右儿子,所以合并后重结点一定会变轻结点。考虑最坏情况,所有轻结点都变成重结点。并且由于轻结点的性质,一条右路径上的轻结点的数量小于。
所以本次合并过程的势能变化为
均摊开销等于势能变化加上实际开销
而n次的均摊开销为
最终平均下来也就是了。
代码示例
C语言代码示例。
struct skew_heap_node
{
int item;
struct skew_heap_node *left;
struct skew_heap_node *right;
};
struct skew_heap_node *skew_heap_merge(struct skew_heap_node *x, struct skew_heap_node *y)
{
if (NULL == y)
{
return x;
}
else if (NULL == x)
{
return y;
}
if (x->item > y->item)
{
struct skew_heap_node *tmp = x;
x = y;
y = tmp;
}
struct skew_heap_node *r = x->right;
x->right = x->left;
x->left = skew_heap_merge(r, y);
return x;
}
struct skew_heap_node *skew_heap_insert(struct skew_heap_node *x, struct skew_heap_node *y)
{
return skew_heap_merge(x, y);
}
struct skew_heap_node *skew_heap_delete_min(struct skew_heap_node *x)
{
return skew_heap_merge(x->left, x->right);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
2021-12-05 docker网络
2020-12-05 证书与密钥的标准
2020-12-05 go接口