当前位置: 首页 > article >正文

数据结构 ——— 向上调整建堆和向下调整建堆的区别

目录

前言

向下调整算法(默认小堆)

利用向下调整算法对数组建堆

向上调整建堆和向下调整建堆的区别​编辑

向下调整建堆的时间复杂度:

向上调整建堆的时间复杂度:

结论 


前言

在上一章讲解到了利用向上调整算法对数组进行建堆
再利用首尾交换和向下调整建堆算法对数组调整成升序或者降序

数据结构 ——— 向上/向下调整算法将数组调整为升/降序-CSDN博客

接下来要学习的是:利用向下调整算法建堆,然后再比较区别


向下调整算法(默认小堆)

static void AdjustDown(HPDataType* a, int size, int parent)
{
	int child = parent * 2 + 1;
 
	while (child < size)
	{
		// 先找到左右孩子中小的那个
		if ((child + 1 < size) && (a[child + 1] < a[child]))
			child++;
 
		if (a[parent] > a[child])
		{
			// 交换
			Swap(&a[parent], &a[child]);
			
			// 迭代
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

推理过程已经在上一章讲解了,这里就不过多赘述


利用向下调整算法对数组建堆

有以下整型数组a:

int a[] = { 5,7,3,9,1,8,4,6,2 };

如何利用向下调整算法对数组建堆呢?

使用向下调整算法的前提是:需要向下调整的数据的左右子树都是堆,才能使用向下调整算法,否则就算使用向下调整算法,也不能建堆
现在的主要问题就是数组 a 不是堆,且数组首元素的左右子树也不是堆

解决办法:

从数组最后一个元素开始往前向下调整建堆
因为向下建堆的前提是要左右子树是一个堆,那么就先把左右子树建堆,左右子树中又会有左右子树,直到根节点,就停止建堆
所以只需要从数组最后一个元素开始往前依次利用向下建堆算法进行建堆,那么就能把数组 a 建立成大堆/小堆
但是必须要从数组的最后一个元素开始建堆吗?
其实不用,因为最后一个元素是叶子节点,叶子节点的特点就是没有孩子节点,那么叶子节点本身就是一个堆

           5

        /      \
     7          3
    /  \        /  \
  9   1      8  4

 / \
6 2

6、2、8、4 都属于叶子节点,那么就不用对这些节点进行向下调整算法
那么只需要从最后一个叶子节点的父亲节点开始往前进行向下调整算法 
假设最后一个叶子节点 2 的下标为 child
那么父亲节点就可以通过 (child-1)/2 这个公式进行计算,2 的父亲节点也就是 9
对 9 进行了向下调整算法后,就需要对 3 这个子树进行向下调整算法
而且找 3 这个节点只需要 9 节点的下标减一即可
依次往前向下调整,最后调整到数组的首元素,那么就完成了对数组 a 进行建堆

代码验证:

           1

        /      \
     2          3
    /  \        /  \
  5   7      8  4

 / \
6 9


向上调整建堆和向下调整建堆的区别

向下调整建堆的时间复杂度:

最后一层是叶子节点,所以不需要使用向下调整算法
从倒数第二层开始,使用向下调整算法进行建堆
倒数第二层有 2^(h-2) 个节点,每个节点最多向下调整 1 次
那么倒数第二层一共向下调整 2^(h-2)*1 次
倒数第三层有 2^(h-3) 个节点,每个节点最多向下调整 2 次
那么倒数第三层一共向下调整 2^(h-2)*2 次
………………
第二层有 2^1 个节点,每个节点最多向下调整 h-2 次
那么第二层一共向下调整 2^1*(h-2) 次
第二层有 2^0 个节点,每个节点最多向下调整 h-1 次
那么第一层一共向下调整 2^0*(h-1) 次

得出时间复杂度表达式:
F(h) = 2^(h-2)*1 + 2^(h-3)*2 + …… + 2^1*(h-2) + 2^0*(h-1)

通过错位相减法简化以上公式得出:
F(h) = 2^h - 1 - h

且假设节点的总个数为 N ,那么高度h和节点N的关系是: 2^h - 1 == N

最后得出向下调整建堆整体复杂度为:
F(N) = N - log(N+1)
大O渐进表示法:O(N) ,(log(N+1)可以忽略不计)

向上调整建堆的时间复杂度:

除了根节点,其他节点都需要使用向上调整算法
第二层有 2^1 个节点,每个节点最多向上调整 1 次
那么第二层一共向上调整 2^1*1 次
………………
最后一层有 2^(h-1) 个节点,每个节点最多向上调整 (h-1) 次
那么最后一层一共向上调整 2^(h-1)*(h-1) 次

得出时间复杂度表达式:
F(h) = 2^1*1 + 2^2*2 + …… + 2^(h-2)*(h-2) + 2^(h-1)*(h-1)

通过错位相减法简化以上公式得出:
F(h) = 2^h*(h-2)+2

且假设节点的总个数为 N ,那么高度h和节点N的关系是: 2^h - 1 == N

最后得出向下调整建堆整体复杂度为:
F(N) = (N+1) * (log(N+1)-2) + 2
大O渐进表示法:O(N*longN)

结论

向下调整算法的时间复杂度低于向上调整算法的时间复杂度
那么也就是向下调整算法的效率高于向上调整算法的效率

所以要对数组进行建堆的话,推荐使用向下调整建堆算法


http://www.kler.cn/a/383561.html

相关文章:

  • UE5 渲染管线 学习笔记
  • 为什么要用云电脑玩游戏?5大好处揭秘,ToDesk云机性能强又易用
  • V900新功能-电脑不在旁边,通过手机给PLC远程调试网关配置WIFI联网
  • AI可信论坛亮点:合合信息分享视觉内容安全技术前沿
  • 软件设计与体系结构
  • pyparsing如何实现嵌套捕获
  • Linux-shell实例手册-磁盘
  • 在Ubuntu 上实现 JAR 包的自启动
  • 强化学习问题设计技巧
  • Spring-Day7
  • springboot020基于Java的免税商品优选购物商城设计与实现
  • 一七四、JavaScript里Object的常用方法及其示例
  • 揭秘全向轮运动学:机动艺术与上下位机通信的智慧桥梁
  • 大模型低秩分解
  • Vue 2 + JavaScript + vuedraggable 集成案例
  • 【Effective C++】阅读笔记3
  • 深入了解逻辑回归:机器学习中的经典算法
  • 【css】overflow: hidden效果
  • 【设计模式】结构型模式(三):桥接模式、外观模式
  • 如何建购物网站提升用户体验
  • 泷羽sec学习打卡-shodan扫描6
  • 完成程序《大奖赛评分B》
  • Python入门资料!笨办法学Python!编程小白的第一本Python入门书!
  • 解决微信小程序电脑能正常使用,手机端无法正常访问的问题
  • 100种算法【Python版】第56篇——Delaunay三角剖分之增量法
  • HTTP返回码和其含义