数据结构 - 二叉堆

二叉堆

简介

二叉堆其实就是二叉树,只不过二叉堆的最顶端的值,要么最大,要么最小,这要根据题意来定。
如图:
参考于:https://www.cnblogs.com/henry-1202/p/9307927.html#_label0
读者注意一下,图上的黑字代表二叉堆的值,而红色则代表下表。

二叉堆的基本操作:插入,删除和查询。

堆的STL实现
本人不太懂,就参考这位大佬的:https://www.cnblogs.com/henry-1202/p/9307927.html#_label0
参考于:https://www.cnblogs.com/henry-1202/p/9307927.html#_label0
上图中,q.top 就是查询,q.pop 就是删除,q.push 就是插入。
下面分享一下这三个操作怎么用代码实现。

int data[10010]; //data数组模拟二叉堆,用来存放数据
int end = 0; //堆中的个数

void swap(int *a, int *b) { //交换函数
	int temp;
	temp = *a; *a = *b; *b = temp;
	return;
}

这是初始化,下面通用。

查询

这个贼简单,就把最顶端那个取出来就可以了。

int top() {
	return data[1]; //返回堆顶
}

插入

这里简单说一下,小根堆的实现。
插入的话,就是将插入的数先放置堆尾。·
然后跟上一层的父域比,如果比他小,就交换,否则退出。
之后以此类推,直到到达对顶。
本人画图拙劣,就不画图展示了。
如果不太懂的话,就去看看这位大佬的图示,意思差不多。
博客链接:https://www.cnblogs.com/henry-1202/p/9307927.html#_label0

emmm,那来看看代码吧!

void push(int x) {
	int now, temp;
	data[++end] = x; //将x直接入堆尾

	now = end; //当前堆的位置
	while (now) { //判断当前的位置在不在根节点
		temp = now >> 1; //找父域,就是指now是temp的左或者右儿子
		if (data[now] < data[temp]) { //判断,成立就交换,否则就结束循环
			swap(&data[now], &data[temp]);
		}
		else break;
		now = temp; //将父域变成子域
	}

	return;
}

这里我再解释一下:
temp = now >> 1;
在这里插入图片描述
看图,0为我要插入的值,其他的数据是堆原有的值,并且都标了下标**(红色的字是下标)**
0作为插入的值,就先到对尾去,下标为10。然后找父域,就是找下标为5的那个。
emmm,注意到没,10 -> 5 ->2 ->1 。这就是这条语句的意思,即当前层的某一个下标为N,
那个他的上层父域为 N>>1 (N/2)。下一层子域为 N<<1 (N*2)。

删除

这也是小根堆。
首先就是,堆顶跟堆尾的值交换一下,就是把要删除的值放到堆尾,然后end减一,即删除了要删除的值。
然后,交换的值,往下走,满足要求就交换,否则结束。
最后判断一下,当前数的下标的子域,是否超过end,超过就结束。
这位大佬的博客可以参考,讲的特详细。
博客链接:https://www.cnblogs.com/henry-1202/p/9307927.html#_label0

void pop() {
	swap(&data[1], &data[end]); //交换,堆顶和堆尾
	end--; //删除堆尾
	int now, temp;
	now = 1; //堆顶的值可能不满足要求,需要往下走,now作为当前值
	while ((now << 1) <= end) { //判断now的子域是否超过end
		temp = now << 1; //这步是now的左孩子,加个一就是右孩子了,这步看不懂,可以看看上面的解释,如果还不行就直接看博客
		if ((temp + 1 <= end) && (data[temp] > data[temp + 1])) { //判断左孩子和右孩子谁满足要求,如果没有右孩子,就直接左孩子
			temp++; //从左孩子到右孩子
		}
		if (data[now] > data[temp]) { 判断,成立就交换,否则就结束循环
			swap(&data[now], &data[temp]);
		}
		else break;
		now = temp; //将子域变成父域
	}

	return;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Vcatory

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

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

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

打赏作者

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

抵扣说明:

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

余额充值