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

news2024/11/6 2:38:56

目录

前言

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

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

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

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

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

结论 


前言

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

数据结构 ——— 向上/向下调整算法将数组调整为升/降序-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.coloradmin.cn/o/2229994.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Handler、Looper、message进阶知识

Android Handler、Looper、Message的进阶知识 在Android开发中&#xff0c;Handler、Looper和Message机制是多线程通信的核心。为了深入理解并优化它们的使用&#xff0c;尤其是在高并发和UI性能优化中&#xff0c;可以利用一些高级特性。 1. Handler的高阶知识 Handler在基本…

【设计模式系列】迭代器模式(七)

一、什么是迭代器模式 迭代器模式&#xff08;Iterator Pattern&#xff09;是一种行为型设计模式&#xff0c;它提供一种方法来顺序访问一个聚合对象中的各个元素&#xff0c;而不暴露其内部的表示。迭代器模式将集合的遍历过程封装在一个独立的迭代器对象中&#xff0c;这样…

C++基础三(构造函数,形参默认值,函数重载,单例模式,析构函数,内联函数,拷贝构造函数)

C有六个默认函数&#xff0c;分别是&#xff1a; 1、默认构造函数; 2、默认拷贝构造函数; 3、默认析构函数; 4、赋值运算符; 5、取址运算符; 6、取址运算符const; 构造函数 构造函数(初始化类成员变量)&#xff1a; 1、属于类的成员函数之一 …

【C语言学习笔记】

C语言发展史&#xff1a; 1960 原型A语言->ALGOL语言 1963 CPL语言1967 BCPL1970 B语言1973 C语言 C语言特点&#xff1a; 基础性语言语法简洁 紧凑 方便 灵活(得益于指针)运算符 数据结构丰富结构化 模块化编程移植性好 执行效率…

智慧城市的守护者——智能井盖监测终端

城市化进程的加速推进使得基础设施建设成为提升城市品质的关键环节。然而&#xff0c;在这一进程中&#xff0c;市政公用设施中的井盖与地下线缆的安全问题却日益凸显。由于缺乏有效的实时监控与管理体系&#xff0c;给犯罪分子留下了可趁之机&#xff0c;频繁发生的井盖被盗及…

C语言 | Leetcode C语言题解之第513题找树左下角的值

题目&#xff1a; 题解&#xff1a; #define MAX_NODE_SIZE 10000int findBottomLeftValue(struct TreeNode* root){int ret;struct TreeNode** queue (struct TreeNode **)malloc(sizeof(struct TreeNode) * MAX_NODE_SIZE);int head 0;int tail 0;queue[tail] root;whil…

HarmonyOS应用开发者基础认证——初级闯关习题参考答案大全

相关文章 HarmonyOS应用开发者中级认证——中级闯关习题参考答案大全 HarmonyOS应用开发者高级认证——高级闯关习题参考答案大全 文章目录 HarmonyOS第一课 HarmonyOS介绍判断题单选题多选题 HarmonyOS第一课 DevEco Studio的使用判断题单选题多选题 HarmonyOS第一课 ArkTS语法…

SpringBoot 集成 Mybatis-Plus,LambdaQueryWrapper 使用方法

&#x1f3dd;️ 博主介绍 大家好&#xff0c;我是 一个搬砖的农民工&#xff0c;很高兴认识大家 &#x1f60a; ~ &#x1f468;‍&#x1f393; 个人介绍&#xff1a;本人是一名后端Java开发工程师&#xff0c;坐标北京 ~ &#x1f389; 感谢关注 &#x1f4d6; 一起学习 &am…

Word文档丢失抢救方法:15 个 Word 文档恢复工具

MS Word 文档恢复的重要性 对于严重依赖 Microsoft Word 创建和编辑文档的个人和企业来说&#xff0c;MS Word 文档恢复是一个至关重要的方面。 文件损坏、系统崩溃和其他意外事件可能会导致 Word 文档中存储的重要数据丢失。 及时恢复这些文档有助于节省时间、精力和资源。 本…

python实战项目51:selenium结合requests获取某众点评评论

python实战项目51:selenium结合requests获取某众点评评论 一、selenium获取cookies二、利用requests发送请求三、注意事项四、完整代码一、selenium获取cookies 首先,初始化selenium的webdriver,然后使用webdriver打开某众点评主页,之后手动扫码登录,利用selenium的get_c…

ETLCloud怎么样?深度解析其在数据管理中的表现

在BI或数据大屏等数据分析工具中&#xff0c;经常需要从多个业务系统中提取原始数据&#xff0c;然后对数据进行清洗、处理&#xff0c;以获取高质量、有效且干净的数据以供后续的BI进行数据统计和分析使用&#xff0c;从高质量的实现企业数据的价值变现。 然而&#xff0c;在…

《花少6》豆瓣评分3.9,“锅”不该周雨彤一个人背

《花儿与少年 第六季》以豆瓣评分3.9成为了整个系列IP有史以来口碑最差的一季节目。 播出过半的《花少6》终于在万众期待下开分了&#xff0c;豆瓣首次开分为4.8&#xff0c;实际上已经是“花少”史上最低评分&#xff0c;紧接着短短几天持续下滑至3.9分&#xff0c;让原本就不…

WPF+MVVM案例实战(十七)- 自定义字体图标按钮的封装与实现(上)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、案例效果1、按钮分类2、BC类按钮实现1、文件创建2、字体图标资源3、自定义依赖属性4、按钮特效样式实现3、案例实现1、案例效果 1、按钮分类 在WPF开发中,最常见的就是按钮的使用,这里我们总…

day-77 超级饮料的最大强化能量

思路 动态规划&#xff1a;因为每一步要么选A&#xff0c;要么选B&#xff0c;所以问题可以转换为求最后一步从A选或从B选中的较大值 解题过程 定义而二维数组dp,dp[i][0]表示最后一步从A取能获得的最大能量&#xff0c;dp[i][1]表示最后一步从B取能获得的最大能量状态转换方程…

91.【C语言】数据结构之单向链表的头删和尾删

目录 1.尾删函数SLTPopBack 代码示例(写入SList.c) 在SList.h中写入该函数的声明 main.c部分代码改为 ​编辑 分析 解决方法 方法1:双指针算法(快指针tail,慢指针pretail) 方法2 2.头删函数SLTPopFront 一个节点示意图 多个节点示意图 代码示例(写入SList.c) 在S…

C语言内幕--全局变量(结合内存分区、汇编视角看类型、连接器)

前言 学习资源&#xff1a;b站up主&#xff1a;底层技术栈学过C语言都知道&#xff0c;全局变量可以再全局中使用&#xff0c;其实全局变量内部还是涉及到不少知识&#xff0c;这里从内存分区、汇编视角看类型、连接器等角度看待全局变量&#xff1b;由于涉及到底层技术&#…

新160个crackme - 089-fornixcrackme1

运行分析 需要破解Name和Serial PE分析 ASM程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 ida搜索找到关键字符串 动态分析关键函数&#xff0c;逻辑如上图&#xff0c;通过Name计算得到char_1&#xff0c;亦或后对比Serial&#xff0c;相等则返回成功信息 分析…

Python爬虫系列(一)

目录 一、urllib 1.1 初体验 1.2 使用urllib下载网页、图片、视频等 1.3 反爬介绍 1.4 请求对象定制 1.5 get请求的quote方法 1.6 多个参数转成ascii编码 1.7 post请求 1.8 综合案例演示 一、urllib 1.1 初体验 # urllib是python默认带的&#xff0c;无需额外下载 i…

动态规划-回文串问题——5.最长回文子串

1.题目解析 题目来源&#xff1a;5.最长回文子串——力扣 测试用例 2.算法原理 1.状态表示 判断回文子串需要知道该回文子串的首尾下标&#xff0c;所以需要一个二维数组且数据类型为bool类型来存储每个子字符串是否为回文子串&#xff0c; 即dp[i][j]:以第i个位置为起始&a…