数据结构——二叉堆

堆是一种拥有弱排序性质的数据结构。

堆是一种树,其中每棵子树的根节点都是这棵树中最小或最大的点,若是最小点,则称为最小堆;反之则称为最大堆。

处理堆的一组算法主要有插入,查询,删除,建堆,改变某个结点的值等。

二叉堆

结构

二叉堆是一种拥有堆性质的完全二叉树。下图展示了一个典型的二叉堆,节点中的数表示权值。
请添加图片描述

算法

在介绍二叉堆的算法前,需要先介绍两种核心操作:向上调整和向下调整

向上调整与向下调整

原理

不满足条件时将叶节点与其根节点互换,实现叶节点的向上调整。向下调整正好相反。

注意

  1. 这两种算法传入的分别是要调整的叶节点和根节点
  2. 在使用数组存储堆的时候,我们将下标为1的结点设为根节点,而下标为0的点可以设置为一个极小或极大的数,以防止在调整位置的时候不小心访问到负数下标,这种方法称为设置哨兵
代码
void up(int x)//向上调整
{
	while (x > 1&&heap[x] < heap[x / 2]) {//heap指表示堆的树
		swap(heap[x], heap[x / 2]);
		x /= 2;
	}
}
void down(int x)//向下调整
{
	while (x * 2 <= n) {
		int t = x * 2;
		if (t < n && heap[t]>heap[t + 1]) t++;
		if (heap[x] >= heap[t]) {
		swap(heap[x], heap[t]);
		x = t;
		}
	}
}

插入

插入指的是将一个已知权值的点插入树中。

原理

先将点连到最右下角的叶节点上,若发现连上点后不满足堆的性质,则将该点与其根节点交换;若仍不满足则继续交换,直到满足为止。

图示
  1. 将点2.5连到点4上(图中的黄色结点和蓝色结点分别是连接后查看是否要调换的两个结点)请添加图片描述

  2. 发现连上后不满足堆的性质,于是将4与2.5调换
    请添加图片描述

  3. 此时满足堆的性质,插入操作完成(如果发现还不满足则要继续向上调整)

代码
void insert(int i) 
{//i是插入的结点权值,n是树的结点总数
	int x = ++n;
	heap[x] = i;
	up(n);
}

查询

原理

堆中的查询都很简单,返回最大值/最小值,即堆顶的元素

代码
int inquire()
{
	return heap[1];
}

删除

原理

删除,指的是从堆中删除根节点,但是如果直接删掉就变成了两个堆,难以处理。

我们采取将根节点与最后一个节点交换,删除最后一个结点(根节点),然后将根节点(最后一个节点)向下调整的方法来完成删除操作。

图示
  1. 原二叉堆(黄色和蓝色分别是两个要交换的点)请添加图片描述
  2. 交换根节点和最后一个结点并将根节点删除请添加图片描述
  3. 发现不满足堆的性质,于是向下调整请添加图片描述
  4. 再次调整,满足堆的性质,调整完成请添加图片描述
代码
	void delete1(int i)
	{
		swap(heap[1], heap[n]);
		n--;
		down(1);
	}

建堆

给定一个无序数组,建成一个二叉堆。有从根结点向上调整和从叶结点向下调整两个方法。

向上调整

从根结点向下一层一层遍历结点,不断向上调整即可。

代码
void build_heap_up()
{
	for (int i = 1; i <= n; i++)up(i);
}
向下调整

从叶节点向上遍历结点,不断向下调整

代码
void build_heap_down()
{
	for (int i = n; i >=1; i--)down(i);
}

改变某个结点的值

改变结点的值之后,要向上或向下调整。

代码
	void change_node(int i, int a, bool x)//i是要改变的结点,a是增加或减小的值,x为0时表示减小,为1时表示增加
	{
		if (x == 0)i -= a;
		else {
			i += a;
		}
		up(i);
		down(i);
	}
  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霜_哀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值