堆的基本知识

1、堆的定义
首先,堆是完全二叉树(二叉树:每个结点有两个子节点),它满足如下性质:
(1)任何一个结点都不大于其父结点,这种堆称为大顶堆 或者 任何一个结点都不小于其父结点,这种堆称为小顶堆
(2)需要是完全二叉树,最后一层在最左侧

2、用数组来存储二叉树
首先给二叉树从左至右,从上至下来给每个结点编号,如此编号后,子结点的左结点是父结点的二倍,子结点的右结点是父结点的2倍加1。
在这里插入图片描述
之后,就可以用如下图的数组来存储这个堆了,该数组从1开始计数,以符合这个堆的索引。
在这里插入图片描述
这里要解释一下的是:
第i个结点的父结点的索引计算公式是:parent(i)=i/2 这里的"/"是计算机里的除号,取整符。
第i个结点的子结点分别是:left child(i)=2i;right child(i)=2i+1。
根据这个公式,就可以在数组中索引相应的结点数据了
3、二叉树shiftUp操作
作用:将插入的元素放到堆的最后一个叶子,并且对堆进行排序,使其成为最大堆。如下图所示:
在这里插入图片描述
方法:由于没插入此元素之前,这个堆是最大堆,新插入的元素要做的就是将它和父结点比较,如果大于父结点,就和父结点调换位置,接下来继续比较调换过父结点和其上一层父结点。直至形成最大堆
代码如下:

void __shiftup(int k)
	{
		while (k>1 && data[k / 2]<data[k])
		{
			std::swap(data[k / 2], data[k]);
			k = k / 2;
		}
	}
void insert(T item)
	{
	//如果堆里的数据超过容纳总量,则报错
		assert(capcity > count + 1);
		//将元素插入数组
		data[count + 1] = item;
		count++;
		//将元素插入完全二叉树,传入参数是数组的最后一个索引
		__shiftup(count);
	}

在第k个节点插入元素,并对其进行shiftup操作。
4、shiftdown操作
作用:从堆中取出一个元素后,将堆排序成最大堆。
从堆中取出元素的方法:先将第一个元素取出,然后将最后一个元素放到第一个元素位置。同时count–。然后将第一个元素与两个子节点比较,如果子节点比该元素大,则交换父结点和子节点的元素。之后继续比较交换过的这个子节点和该子节点下面的子节点。
如下图:先取出data[1],然后将data[11]和data[1]交换

交换后形成下图的这个二叉树。
在这里插入图片描述
由于该二叉树的data[1]<子节点的最大值data[2],所以需要将data[1]与data[2]交换
在这里插入图片描述
接下来继续比较data[2]他的两个子节点data[4],data[5]。这里,需要交换data[2]和data[5]。形成下图所示的树。
在这里插入图片描述
代码如下:

	void __shiftdown(int k)
	{
	//如果左子节点存在,则需要一直执行shiftdown操作
		while (2 * k <= count)
		{
		//如果存在右子节点,比较左右子节点,将大的节点的索引放到j里面
			int j = 2 * k;
			if (2 * k + 1 <= count&&data[j]<data[2 * k + 1])
			{
				j = 2 * k + 1;
			}
			//如果父结点小于左子节点,则调换位置
			if (data[k]<data[j])
			{
				swap(data[k], data[j]);
			}
			else
			{
				break;
			}
		}
	}
	T extraMax()
	{
		T result = data[1];
		data[1] = data[count];
		count--;
		__shiftdown(1);
		return result;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值