当前位置: 首页 > 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

相关文章:

  • 运维高可用架构设计
  • Oh My Posh安装
  • 基于Spring Boot+Vue的助农销售平台(协同过滤算法、限流算法、支付宝沙盒支付、实时聊天、图形化分析)
  • 关于在GitLab的CI/CD中用docker buildx本地化多架构打包dotnet应用的问题
  • pil分割图片
  • 数据库->索引
  • 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返回码和其含义