数据结构堆的基本操作实现

堆 其实就是一棵完全二叉树(见下图)在数组中的实现
堆分为大根堆和小根堆
大根堆:1.根节点最大 2.子节点必须大于等于父节点
小跟堆:1.根节点最小 2.子节点必须小于等于父节点
一个大根堆
在数组中存储这种结构时,总是习惯将根节点存储在数组下标为1的位置
每一个下标为k的节点的父节点的下标就是k/2
每一个下标为k的节点的子节点的下标就是k*2和 k * 2+1

在对堆进行操作(插入或删除了一个元素)的时候,有时会打破堆的有序性,使得子节点和父节点之间的有序性被打破,这时候就需要重新恢复堆的有序性。
恢复堆的有序性需要两个核心的方法
一、上浮(以大根堆为例)

void swim(int x)//x为要进行上浮操作的元素在数组中的下标
{
//当发现这个元素比它的父节点要大的时候,就说明堆的有序性已经被打破了
//此时就需要将这个节点与它的父节点的值进行交换
//然后重复此操作,直到无法上浮为止
	while(x>1&&a[x]>a[x/2])
	{
		exch(x,x/2);
		x/=2;
	}
}

二、下沉 (以大根堆为例)

void sink(int x)
{
//因为每一个节点最多可以有两个子节点,因此下沉操作显得比上浮操作更加繁琐
//x*2<=n和x*2+1<=n这个判断不可缺少,并且需要放在逻辑表达式的前面
//因为只有当这个下标在合法的范围内,才能根据这个下标去访问元素
//这里的两个逻辑表达式是说当前节点小于任何一个子节点的时候,就进行下沉
	while(x*2<=n&&a[x]<a[x*2]||x*2+1<=n&&a[x]<a[x*2+1])
	{
	//能进入到这里,说明上面两个逻辑表达式至少有一个满足
	//现在考虑这样一种情况:x*2下标是合法的
	//但是x*2+1就超出了此时堆的最大下标,所以需要加一个判断
		if(x*2+1<=n)
		{
		//如果两个子节点都存在,那么就取两个之中大的那一个与当前节点交换
		//因为当进入到这里面的时候,其实是不知道当前节点到底是比哪一个节点小
		//所以选择相对大的那个节点
			if(a[x*2]>a[x*2+1]){
				exch(x,x*2);
				x*=2;
			}else
			{
				exch(x,x*2+1);
				x=x*2+1;
			}
		}else
		{
			exch(x,x*2);
				x*=2;
		}
		
	}
	
}

三、插入元素(从0开始构建一个堆)
假设要从键盘输入N个数,然后以这N个数构建一个大根堆
构建堆的基本思想就是将要插入的元素插入到数组的末尾
然后对这个元素进行上浮操作
代码如下

//n用来表示堆的最大下标
int N,n=0,a[10];
cin>>N;
int t;
while(N--)
{
	n++;
	cin>>a[n];
	swim(n);
{

四、删除根节点
以大根堆为例,删除根节点就是删除最大元素
基本思想是将根节点与数组最后一个元素进行交换,然后对交换后的根节点实施下沉操作

void exch(int i,int j)
{
	int t=a[i];
	a[i]=a[j];
	a[j]=t;
}

exch(1,n);
n--;
sink(1)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值