<<数据结构>>向上调整建堆和向下调整建堆的分析(特殊情况,时间复杂度分析,两种建堆方法对比,动图)

news2024/11/17 18:10:51

今天,我来讲讲建堆算法中使用向上调整和向下调整。



目录

    • 建堆的应用
    • 向上调整建堆
    • 向下调整建堆
    • 向下调整建堆和向上调整建堆的选择



建堆的应用

在数据结构模拟堆中,我们可能会通过输入数组的元素来进行建堆或者在堆排序中,我们也需要建堆,那么建堆就有两种方法,一种从倒数第二层最右侧的父节点开始进行向下调整,直到把所有父节点都向下调整完;另外一种是从最后一个结点开始向上调整,直到每个结点都进行一次向上调整。

物理结构:实实在在在内存中是如何存储的
逻辑结构:想象出来的结构

如下面有一个数组,物理结构和逻辑结构分别如下:
在这里插入图片描述
如上面数组的逻辑结构,即不满足大堆,也不满足小堆,那么我们就应该进行建堆。假设要建大堆。

接下来,我来依次进行向上调整建堆和向下调整建堆。



向上调整建堆

如上面所说,我们需要找到最后一个结点,进行向上调整,如下
在这里插入图片描述
这个为向上调整建堆的第一趟,接下来,将倒数第二个结点继续建堆,即43,持续下去,直到把所有的结点都进行了向上调整,那么就完成了建堆的任务。

但是这样调整真的可以吗?
下面是代码:

int swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
Build_BigHeap(int* arr,int n)
{                                   //错误示范
	for (int i = n - 1; i >= 0; i--)//从最后一个结点开始,保证每个结点都能向上调整
	{
		int child = i;
		int parent = (child - 1) / 2;
		while (child > 0)              //单趟向上调整
		{
			if (arr[child] > arr[parent])
			{
				swap(&arr[child],&arr[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
			{
				break;
			}
		}
	}
}
int main()
{
	int arr[] = {12,19,5,25,36,10,3,30,15,2,14,20,30,43,30};
	Build_BigHeap(arr,sizeof(arr)/sizeof(arr[0]));
	return 0;
}

建堆前:
在这里插入图片描述

建堆后:
在这里插入图片描述

观察可以发现,在我们建堆后的逻辑结构,大部分结点都满足了大堆的要求,即父节点大于、等于孩子结点,但是有一个父结点的值小于孩子结点,是哪个呢?就是19和25,这就奇怪了,其他结点都满足大堆的要求,为什么偏偏有两个结点不满足大堆的要求呢?不着急,我要画个小动图分析一下。

由于上面的问题由第八趟向上调整导致,我就不从第一趟排序画到问题出现的地方了,因为其他的几趟的向上调整并不是影响该问题的出现的因素。但是由于前面的调整没画,此次的第八趟向上调整与从第一次向上调整画到第八趟的向上调整结果有些不同,但是并不影响,因为我们主要分析的是19和25位置的原因所在。

在这里插入图片描述

上面就是25出现在了19后面的原因,所以我们最开始选择最后一个元素来进行向上调整,接着依次往上找结点进行向上调整的方法存在着小bug,比如第八趟向上调整中,将25调到了最后面的一层,然后,程序就继续去向上调整数字3的位置了,却不知道25还需要与19进行调整。

那么,我应该如何改进这个bug呢,我们直接选择从第二个结点开始,也就是下标为1的位置进行向上调整,接下来,程序依次调整到最后一个结点的位置,那么就不会有问题了。

代码如下:

int swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
Build_BigHeap(int* arr,int n)
{
	for (int i = 1; i <= n - 1; i++)//从第二个结点开始调整,保证每个结点都能向上调整
	{
		int child = i;
		int parent = (child - 1) / 2;
		while (child > 0)              //单趟向上调整
		{
			if (arr[child] > arr[parent])
			{
				swap(&arr[child],&arr[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
			{
				break;
			}
		}
	}
}
int main()
{
	int arr[] = { 12,19,5,25,36,10,3,30,15,2,14,20,30,43,30 };
	Build_BigHeap(arr, sizeof(arr) / sizeof(arr[0]));
	return 0;
}

建堆前
在这里插入图片描述

建堆后
在这里插入图片描述

现在,该向上调整建堆的代码就满足要求了。

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

假设最坏的情况下,每个结点都需要向上调整
在这里插入图片描述
由二叉树的性质可以得知,每层结点的个数是2^(h-1),在第几层的结点如果需要调整的话,最多需要向上调整h-1次。

那么,调整次数将与高度相关,如下
在这里插入图片描述



向下调整建堆

在向下调整建堆中,我们需要找到最后一个父节点,将该父节点与他的孩子结点进行比较,如果需要交换就进行交换,接下来,继续拿其他的父节点进行相同的比较,直到把所有的父节点比较完成,那么向下调整建堆就完成了。

假设我们需要建大堆,那么我们就先找到最后一个父结点,选出该父结点两个孩子结点中最大的那个结点,将该最大的孩子结点与父节点进行交换,这样就满足了大堆的要求了。

如下:第一趟向下调整的动图
在这里插入图片描述
由该动图可以得知,该替换后的父节点与他的孩子结点就满足了大堆的要求了,接下来,继续往前调整,直到把所有的父节点调整完,那么整个就满足了大堆了要求了。

我再举一个调整例子吧,我并没有一步一步调整上去,而是直接调整5结点,方便大家理解代码,所以下图的10结点还没有调整。
在这里插入图片描述

代码如下:

int swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
Build_BigHeap(int* arr, int n)
{
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)//从最后一个父节点结点开始调整,保证每个父结点都能向下调整
	{
		int parent = i;
		int child = parent * 2 + 1;
		while (child < n)              //单趟向下调整
		{
			if (arr[child + 1] && arr[child + 1] > arr[child])
			{
				child++;
			}
			if (arr[child] > arr[parent])
			{
				swap(&arr[child], &arr[parent]);
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}
}
int main()
{
	int arr[] = { 12,19,5,25,36,10,3,30,15,2,14,20,30,43,30 };
	Build_BigHeap(arr, sizeof(arr) / sizeof(arr[0]));
	return 0;
}

建堆前:
在这里插入图片描述

建堆后:
在这里插入图片描述

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

假设在最坏的情况下,所有的结点都需要向下调整。
在这里插入图片描述
那么时间复杂度的计算如下:
在这里插入图片描述



向下调整建堆和向上调整建堆的选择

向上调整建堆的时间复杂度是:O(N*logN)
向下调整建堆的时间复杂度是:O(N)
所以,大多数都会选择向下调整建堆。



如果觉得写得不错,可不可以动动小手,三连支持一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/160050.html

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

相关文章

Kubernetes之网络排查详细文

文章目录前言一、Pod 网络异常1.1 网络异常大概分为如下几类&#xff1a;1.2 那么整个 Pod 网络异常分类可以如下图所示&#xff1a;二、常用网络排查工具2.1 tcpdump2.1.1 抓取示例2.1.2 选项分组2.1.3 过滤 TCP 标记位2.1.4 查找 http 包2.1.5 查找 DNS 流量2.1.6 查找对应流…

财务数字化在企业数字化转型中起到什么作用?

财务数字化在企业数字化转型中起到什么作用&#xff1f;许多企业在推动各大业务部门进行数字化转型时&#xff0c;往往会忽略财务部门。然而&#xff0c;作为掌握公司核心资源与数据和推动企业数字化建设的部门&#xff0c;财务也应成为企业数字化转型的重要突破口。 这篇就用…

Unity 之 Addressable可寻址系统 -- 可寻址系统使用介绍 -- 入门(三)

可寻址系统设置面板使用介绍介绍 -- 入门&#xff08;三&#xff09;一&#xff0c;可寻址系统目录介绍二&#xff0c;可寻址系统面板介绍2.1 Groups - 资源组2.2 Settings - 设置2.3 Profiles - 配置文件2.4 Event Viewer - 事件查看器2.5 Analyze - 分析工具2.6 Hosting - 托…

sklearn GridSearchCV网格搜索和SVM的两个参数 C 和 gamma

GridSearchCV&#xff0c;它存在的意义就是自动调参&#xff0c;只要把参数输进去&#xff0c;就能给出最优化的结果和参数。GridSearchCV用于系统地遍历多种参数组合&#xff0c;通过交叉验证确定最佳效果参数。 引用自&#xff1a;公众号&#xff1a; 写bug的程旭源 个人博客…

学生信息管理系统【JDBC+JS+MYSQL+HTML+JSP+Servlet】(一)

第一次发综合项目&#xff0c;无论是前端还是后端&#xff0c;都应用到了&#xff0c;项目写的很完整&#xff0c;我将分为四篇文章把项目代码写完&#xff0c;多多支持 一&#xff1a;项目背景 学生成绩管理系统是基于互联网的信息管理平台&#xff0c;主要提供成绩录入和查…

黄金的几种征兆

有别于股票、基金等的投资品种&#xff0c;由于现货黄金采用保证金的交易制度&#xff0c;因而使投资者有爆仓的可能。具体而言&#xff0c;爆仓是指在某些特殊条件下&#xff0c;投资者保证金账户中的客户权益变为负值的情形。在黄金交易的实战中&#xff0c;客户爆仓大多与资…

一文搞懂Spring,堪称Spring源码终结者

Spring的影响力想必无需与大家多说&#xff0c;如果你用spring&#xff0c;那么读读源码有助于对你最重要的工具的理解&#xff0c;好的框架源码也可以帮助我们理解什么是好代码。 刚参加工作那会&#xff0c;没想过去读源码&#xff0c;更没想过去改框架的源码&#xff1b;甚…

反序列化渗透与攻防(一)之PHP反序列化漏洞

前言 序列化和反序列化几乎是工程师们每天都要面对的事情&#xff0c;但是要精确掌握这两个概念并不容易&#xff1a;一方面&#xff0c;它们往往作为框架的一部分出现而湮没在框架之中&#xff1b;另一方面&#xff0c;它们会以其他更容易理解的概念出现&#xff0c;例如加密、…

干货 | 涉疫数据的安全应用方案

以下内容整理自清华大学《数智安全与标准化》课程大作业期末报告同学的汇报内容。第一部分&#xff1a;涉疫数据分类及问题剖析一、涉疫数据分类我们以新冠肺炎疫情为例&#xff0c;构建数据图谱&#xff0c;将涉疫数据分为三个大类&#xff0c;八个小类&#xff0c;共分为50项…

数字化营销,为何网站如此重要?

无论你在哪个行业&#xff0c;客户都会期望你有一个网站。没有网站的公司会发出信息&#xff0c;说他们已经停止运营&#xff0c;或者更糟的是&#xff0c;他们与客户失去了直接的联系。 通常企业的自有媒体由您的网站和社交媒体帐户组成。媒体付费广告等赢利媒体的数据不在您的…

你想要的100套HTML模板

好/看/的/网/页/这/都/有/ 目录 01 HTML 02 效果显示 03 文件演示 04 获取文件 源码链接 获取源码&#xff1f;私信&#xff1f;关注&#xff1f;点赞&#xff1f;收藏&#xff1f; 网页设计 Web design 2023/01/12 “Creativity is allowing yourself to make mista…

岁末年初再添佳誉丨Kyligence 荣获多个奖项及榜单认可

过去的一年&#xff0c;Kyligence 持续创新和打磨企业级产品&#xff0c;以全球领先的指标中台及多维数据库产品在金融、零售、制造、医疗等多个行业场景中逐步落地&#xff0c;实现数智化管理与业务的深度融合。岁末年初&#xff0c;Kyligence 再添佳誉&#xff0c;技术产品、…

第二章.线性回归以及非线性回归—多元线性回归

第二章.线性回归以及非线性回归 2.6 多元线性回归 1.特征&#xff1a; 1).单特征&#xff1a; 2).多特征&#xff1a; 有多少个特征就有多少个未知数x 2.多元线性回归模型的使用场景&#xff1a; 当Y值的影响因素不是唯一时&#xff0c;采用多元线性回归。 3.梯度下降法求解…

【自然语言处理】【chatGPT系列】大语言模型可以自我改进

大语言模型可以自我改进《Large Language Models Can Self-Improve》论文地址&#xff1a;https://arxiv.org/pdf/2210.11610.pdf 相关博客 【自然语言处理】【chatGPT系列】大语言模型可以自我改进 【自然语言处理】【ChatGPT系列】WebGPT&#xff1a;基于人类反馈的浏览器辅助…

python 波士顿房价预测

数据集地址&#xff1a;Index of /ml/machine-learning-databases/housing (uci.edu) 数据集中共有506条样本数据&#xff0c;每条样本包含了13个影响房价的特征。 数据集格式 0.00632 18.00 2.310 0 0.5380 6.5750 65.20 4.0900 1 296.0 15.30 396.90 4.98 2…

openlayers浅入(了解框架逻辑以及简单使用)

openlayers浅入&#xff08;了解框架逻辑以及简单使用&#xff09; 项目需求&#xff0c;使用openlayers替换天地图api开发&#xff0c;记录openlayer的使用 简介 OpenLayers是一个用于开发WebGIS客户端的JavaScript包&#xff0c;最初基于BSD许可发行。OpenLayers是一个开源的…

1575_AURIX_TC275_MTU简介以及部分寄存器

全部学习汇总&#xff1a; GitHub - GreyZhang/g_TC275: happy hacking for TC275! 从今天开始看一个全新的模块介绍MTU&#xff0c;存储测试单元。 TC275中所有的ECC、内置测试以及存储冗余等都有一个统一的接口规范。MTU负责管理所有的存储测试功能。MTU主要有两套寄存器&am…

【iOS】系统框架

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言熟悉系统框架多用块枚举&#xff0c;少用for循环for循环使用Objective-C 1.0的NSEnumerator遍历快速遍历基于块的遍历方式对自定义其内存管理语义的collection使…

Wechaty API 方法 文档整理

背景&#xff1a;刚使用wechaty的时候&#xff0c;对一个不熟悉初学者来说&#xff0c;看官方文档比较费时间&#xff0c;所以把方法和描述集合在一张表上&#xff0c;再使用的时候找对应的方法会比较直观。 中文文档&#xff1a; 介绍 - Wechatyhttps://wechaty.gitbook.io/…

【docker15】docker网络

1.docker网络是什么 docker不启动&#xff0c;默认网络情况 ens33lovirbr0 在CentOS7安装过程中&#xff0c;如果有选择相关虚拟化的服务安装系统后&#xff0c;启动网卡时会发现有一个网桥连接的私网地址的virbr0网卡&#xff08;virbr0网卡&#xff1a;它还有一个固定的默认…