【数据结构】对于堆中向上调整和向下调整的分析

堆的向上调整算法

  现在我们给出一个数组,逻辑上看成是一颗完全二叉树,我们通过根节点逐渐开始向上调整算法可以将其调整为一个小堆
  堆的向上调整有一个前提,那就是当前结点前面的元素已经满足成为堆的条件,这样从当前结点开始向上调整才是有意义的

思路

  当我们得到一个数组,想要利用向下调整的算法将这个数组变成一个堆的形式。
  那么我们就要从根节点开始也就是从下标为0的位置开始向上调整,由于此时只有一个元素,默认已经是一个堆了,也就是[0.0]范围内的元素已经满足堆的条件,此时我们在将调整范围扩大到[0,1],从下标为1的地方开始向上调整,使[0,1]范围内的元素满足称为堆的条件,再将调整范围扩大到[0,2]……直到调整范围为[0,n]时,整个数组从下标为0的地方开始到下标为n的地方都已经按照建堆的规矩排列好了,此时,堆也就建成了。

代码实现

void adjustUp(int* arr,int index)
{
	while (arr[index] > arr[(index - 1) / 2])
	{
		swap(arr, index, (index - 1) / 2);
		index = (index - 1) / 2;
	}
}
void HeapInit(int* arr,int sz)
{
	for (int i = 1; i < sz; i++)
	{
		adjustUp(arr, i);
	}
}

时间复杂度分析

在这里插入图片描述

推导过程:
在这里插入图片描述
因此向下调整建堆的时间复杂度为O(N)

堆的向下调整算法

  当我们给出一个数组,逻辑上看成是一个完全二叉树,我们通过从根节点开始向下调整算法可以把它调整为一个小堆
  但是向下调整算法有一个前提,那就是左右两个子树必须也是一个堆,才能进行调整

思路

  倘若从根节点开始调整,由于由于根节点的左右两个子树并不是堆,所以调整过后也无法将该数组变成一个堆
  所以,我们应该从数组后面进行调整,当位于树的最后一层时,由于没有左右子树,此时向下调整是没有意义的,正确的做法是从倒数第二层最右侧的节点开始向下调整
  这个倒数第二层最右侧的节点并不难求出,它其实就是最后一个节点的父节点

代码实现

void adjustDown(int* arr,int index,int sz)
{
	while (index * 2 + 1 < sz)
	{
		int left = index * 2 + 1;
		int min = left + 1 < sz && arr[left + 1] < arr[left] ? left + 1 : left;
		if (arr[min] < arr[index])
		{
			swap(arr, min, index);
			index = min;
		}
		else
		{
			break;
		}
	}
}
void HeapInit(int* arr,int sz)
{
	for (int i = (sz - 1 - 1) / 2; i >= 0; i--)
	{
		adjustDown(arr, i, sz);
	}
}

时间复杂度分析

因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的就是近似值,多几个节点不影响结果)
在这里插入图片描述
推导过程:
在这里插入图片描述
因此向下调整建堆的时间复杂为O(N)

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值