机械转码日记【4】——向上,向下调整法建堆的时间复杂度;堆排序为什么升序建立大堆,降序建立小堆?

目录

前言

向上调整法的时间复杂度计算

 向下调整法的时间复杂度计算

 为什么升序建立大堆,降序建立小堆?

如果实现升序建立的是小堆会发生什么呢?

前言

向下调整法建堆的时间复杂度为O(N),向上调整法建堆的时间复杂度为O(N*LogN),他们的时间复杂度是如何计算的呢?堆排序中,实现升序就建立大堆,实现降序就建立小堆,又是为什么呢?这篇文章将为铁汁们解答这两个问题。

向上调整法的时间复杂度计算

如何实现向上调整法建堆呢?其实与堆的插入原理相同,就是遍历一个数组,对数组中的每个元素都进行向上调整,遍历完后,这个数组就变成堆啦!代码实现如下:

//向上调整算法
//a为需要修改的堆的地址,child为向上调整时,孩子节点的下标
void AdjustUp(HPDataType* a, size_t child)
{
	assert(a);
	size_t parent = (child - 1) / 2;
	while (child > 0)
	{
		//大堆
		//if (a[child] > a[parent])
		//小堆,如果孩子比父亲小,就交换
		if (a[child]<a[parent])
		{
			Swap(&a[child],&a[parent]);
			child = parent;
			parent = (parent - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
//size是需要建堆数组的元素个数
for (int i = 0; i < size; i++)
	{
		AdjustUp(a, i);
	}

向上调整的时间复杂度计算过程如下:

 

 向下调整法的时间复杂度计算

向下调整法建堆的方式略有不同,因为向下调整法有个前提,只有当左右子树为堆时才可以向下调整,因此我们需要倒着,从倒数第一个非叶子节点开始,一直到根节点递减,都进行向下调整,代码实现如下:

//向下调整算法
//a为需要修改的堆的地址,size为堆的有效数据个数,root为向下调整时根节点的下标
void AdjustDown(HPDataType* a, size_t size, size_t root)
{
	assert(a);
	size_t parent = root;
	size_t child = parent * 2 + 1;
	while (child<size)
	{
		//先找出那个较小的孩子
		//判断大小的同时要注意是否有右孩子节点,即是否造成数组越界
		if (child + 1 < size && a[child + 1] < a[child])
		{
			child++;
		}
		//小堆,如果爸爸比孩子大,就往下调整
		if (a[parent] > a[child])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

for(int i = (n-1-1)/2;i>=0;i--)
{
         AdjustDown(a, n, i);
}

向下调整法的时间复杂度计算过程如下:

 

 为什么升序建立大堆,降序建立小堆?

如果实现升序建立的是小堆会发生什么呢?

假如建立的是如下图小堆:

  1.  最小的数已经在堆顶的位置上
  2. 但是除了堆顶以外,剩下的数都不是有序的,如果需要找出剩下的数中最小的数,需要重新建堆,建堆最少需要O(N)个时间复杂度,而N个数,需要O(N*N)个时间复杂度,这样排序的时间复杂度太大,还不如直接遍历排序。
  3. 所以需要建立大堆,堆顶是最大的数,然后同最后一个数交换,再把交换后的堆顶数向下调整,然后重复交换再向下调整新堆顶数,直到实现排序(具体实现过程可以看上一篇博客机械转码日记【3】——《数据结构》堆的实现及堆的应用_逗你笑出马甲线的博客-CSDN博客)。

降序建立小堆的原因也是这样,为了防止篇幅过长,这里就不再赘述了。

  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

逗你笑出马甲线

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

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

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

打赏作者

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

抵扣说明:

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

余额充值