堆的向上与向下调整

news2024/11/13 9:47:14

目录

一、堆

1、概念

2、性质

二、向上调整

 三、向下调整

四、建堆的比较

1.向上调整建堆

2.向下调整建堆

3.比较

五、总结


一、堆

1、概念

如果有一个关键码的集合K = {k0k1,k2,…kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<=K2i+2 ,则称为小堆(或大堆)。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

2、性质

堆是一颗完全二叉树。

堆的根(父亲)结点的值总是不大于或不小于孩子结点的值。

左孩子=父亲*2+1____ 右孩子=父亲*2+2。

二、向上调整

如果已经存在堆,再插入一个结点,从插入的结点开始,向上依次调整。

调整:如果插入的结点不需要调整,即插入该结点,依旧是堆。

           如果插入的结点不满足堆结构,就要对该结点的父亲结点调整,

调整完因为改变了父亲结点,就要迭代调整新的孩子结点。

图解:

 代码实现:

//建大堆
void AdjustUp(HPDataType*a, int child)
{
	assert(a);
	int parent = (child - 1) / 2; //父亲结点
	while (child>0)
	{
		if (a[parent] < a[child])//大堆,孩子大于父亲就换
		{
			Sweap(&a[parent], &a[child]);
			child = parent;  //向上走 父亲变成孩子
		}
		else
		{
			break;
		}
		parent = (child - 1) / 2;//迭代求出新父亲结点
	}
}

循环结束的条件是孩子不为根结点或者已经是堆结构

 三、向下调整

从根开始向下调整,但是根的左子树和右子树必须是堆。

思路:

parent从跟结点开始

找到左右孩子中大的一个,如果左右孩子中大的一个大于根结点,就交换

由于交换了父亲结点和孩子结点,就要对交换的孩子子树进行向下调整

在调整中,必须注意孩子结点越界问题。

图解:

 代码:

void AdjustDown(HPDataType* a, int parent, int n)
{
	assert(a);
	int child = parent * 2 + 1;
	while (child<n)
	{
		//找左 右孩子大的一个,如果右子树不存在,大的就是左树
		if (child+1<n &&a[child] < a[child + 1])
		{
			child++;
		}
		if (a[parent] < a[child])
		{
			Sweap(&a[parent], &a[child]);
			parent = child;   //迭代调整下一棵子树
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
		
	}
}

四、建堆的比较

建堆有俩种方式,向上和向下调整建堆,衡量一个算法的好坏,通常关注时间复杂度和空间复杂度。本文将以时间复杂度的比较,细说向上调整建堆和向下调整建堆算法。

1.向上调整建堆

向上调整建堆的思路:

1.依次插入结点。从第二个结点开始,比较孩子和父亲,如果是堆就继续比较下一个结点。如果不是就交换父亲和孩子的值,迭代向上比较。

2.比较完(孩子为0),比较下一对。

图解:

 代码实现:

 typedef int HPDataType;

 void Sweap(HPDataType* a, HPDataType* b)
 {
     HPDataType tmp = *a;
     *a = *b;
     *b = tmp;
 }
 //建大堆
 void AdjustUp(HPDataType* a, int child)
 {
     assert(a);
     int parent = (child - 1) / 2; //父亲结点
     while (child > 0)
     {
         if (a[parent] < a[child])//大堆,孩子大于父亲就换
         {
             Sweap(&a[parent], &a[child]);
             child = parent;  //向上走 父亲变成孩子
         }
         else
         {
             break;
         }
         parent = (child - 1) / 2;//迭代求出新父亲结点
     }
 }

 void CreatTree(int* a, int n)
 {
     for (int i = 1; i < n; i++)
     {
         AdjustUp(a, i);
     }

 }

向上建堆时间复杂度:
图解:

 

2.向下调整建堆

思路:

最后一个孩子的父亲结点开始依次进行向下调整,直到根结点。

过程相对简单,画图请自行推导

代码实现:

 typedef int HPDataType;

 void Sweap(HPDataType* a, HPDataType* b)
 {
     HPDataType tmp = *a;
     *a = *b;
     *b = tmp;
 }
 //建大堆
 void AdjustDown(HPDataType* a, int parent, int n)
 {
     assert(a);
     int child = parent * 2 + 1;
     while (child < n)
     {
         //找左 右孩子大的一个,如果右子树不存在,大的就是左树
         if (child + 1 < n && a[child] < a[child + 1])
         {
             child++;
         }
         if (a[parent] < a[child])
         {
             Sweap(&a[parent], &a[child]);
             parent = child;   //迭代调整下一棵子树
             child = parent * 2 + 1;
         }
         else
         {
             break;
         }

     }
 }

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

 }

关于最后一个孩子的父亲下标:

最后一个孩子下标:n-1

孩子的父亲坐标:(n-1-1)/2

计算时间符复杂度:

 3.比较

同样在最坏情况下

向上建堆的时间复杂度为: N*logN

向下建堆的时间复杂度为:N

一个简单的记法:

向上建堆,第二层向上要调整一次,越深层,调整的次数越多,最后一层是2^(h-1)*(h-1)次

是大*大

向下建堆:第一层要调整h-1次,是最多,越深层越少。最后一层是2^(h-1)*0次,是大*小

因此向下调整算法是一种极为优越的算法。

在建堆,我们通常用向下调整算法。

五、总结

堆是一种优越的数据结构,在堆中学习了向上和向下调整算法。

其中向下调整是优越的算法,它的时间复杂度是O(N)

掌握堆的建立,在今后的堆排序、TopK,优先级队列都能柔韧有余。

本文到此结束,感谢阅读!

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

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

相关文章

怎么学习PHP错误处理和调试? - 易智编译EaseEditing

学习PHP错误处理和调试技术可以通过以下步骤&#xff1a; 理解错误类型&#xff1a; 了解PHP中常见的错误类型&#xff0c;如语法错误、运行时错误和逻辑错误等。学习它们的特点和常见原因&#xff0c;以便更好地定位和解决问题。 错误报告设置&#xff1a; 在开发环境中&am…

【Java基础学习打卡14】Java注释

目录 前言一、什么是注释二、注释的重要性三、单行、多行注释1.单行注释2.多行注释 四、文档注释1.文档注释2.JDK官网文档3.javadoc生成文档 五、注释建议总结 前言 本文介绍Java注释&#xff0c;它是我们在Java编程中必不可少的。Java注释有单行注释、多行注释和文档注释。对…

BUUCTF Web CyberPunk WriteUp

想直接查看payload的点这里 前言 二次注入&#xff08;Second-Order Injection&#xff09;是指攻击者在应用程序中注入恶意数据&#xff0c;然后在稍后的操作或不同的上下文中再次使用该恶意数据&#xff0c;导致安全漏洞。它通常发生在数据库查询、数据导出、报告生成等过程…

基于springboot博客论坛系统设计与实现(源码+文档LW+数据库+报告)

HBLOG 是一个博客论坛网站&#xff0c;分为游客端和管理员端。游客端主要有注册登录&#xff0c;查看文章&#xff0c;发表撰写文章&#xff0c;管理自己的文章&#xff0c;评论文章等功能&#xff1b;而管理员端主要有登录&#xff0c;查看近期数据&#xff0c;查看日志&#…

如何做好迭代回顾 2/4

事故根因分析&#xff1a;上集 北京某软件开发公司&#xff0c;专门为电信供应商做定制软件开发&#xff0c;比如发短信做些推广活动等。公司希望做过程改进&#xff0c;我首次与公司老板访谈&#xff1a; 我&#xff1a;过程改进主要帮助管理层更好达到公司业务目标。你们自己…

365天深度学习训练营-第T5周:运动鞋品牌识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 我的环境&#xff1a; 语言环境&#xff1a;Python3.10.7编译器&#xff1a;VScode深度学习环境&#xff1a;TensorFlow2 一、前期工作&#xff1a; 1、导入…

【活动】如何在工作中管理情绪

写在前面 近期发生的新闻热点再度引发公众对稳定情绪和心理健康的关注。有时候我们遇到的最大的敌人&#xff0c;不是运气也不是能力&#xff0c;而是失控的情绪和口无遮拦的自己。如何在工作中保持稳定的情绪&#xff1f;谈谈我的看法。 愤怒的危害 说到愤怒这种情绪&#xf…

基于深度学习的高精度鸟类目标检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度鸟类目标&#xff08;鹦鹉&#xff08;Crested Myna&#xff09;、麻雀&#xff08;Eurasian Tree Sparrow&#xff09;、黑头文鸟&#xff08;Chestnut Munia&#xff09;、白领翡翠&#xff08;Collared Kingfisher&#xff09;、太阳鸟…

【C语言】进阶指针(二)—>函数指针与回调函数

目录 前言&#xff1a; 一、函数指针 代码1分析&#xff1a; 代码2分析&#xff1a; 二、函数指针数组 三、指向函数指针数组的指针 四、回调函数&#xff08;模拟实现库函数qsort&#xff09; &#xff08;一&#xff09;void*类型指针的作用 &#xff08;二&#xf…

Spark—Shell命令对WordCount案例的基本操作(统计、去重、排序、求平均值及join)

一、统计、去重 1、案例数据介绍 WordCount统计&#xff1a;某电商网站记录了大量的用户对商品的收藏数据&#xff0c;并将数据存储在名为buyer_favorite的文本文件中。文本数据格式如下&#xff1a; 2、启动spark-shell 配置好spark环境&#xff0c;若还没有环境可以参考…

windows下环境问题总结

nacos 启动后在spring 项目中无法加载yml配置文件 spring.datasource.platform mysql 注意一定要放开这行&#xff0c;不放的话&#xff0c;可能会导致服务可以成功注册&#xff0c;但是&#xff0c;我们无法使用局部的 nacos里yml配置文件的属性

Linux:项目自动化构建工具——make/Makefile

文章目录 一.make与Makefile的关系1.Makefile2.make 二.项目清理1.clean2. .PHONY 前言&#xff1a; 本章主要内容有认识与学习Linux环境下如何使用项目自动化构建工具——make/makefile。 一.make与Makefile的关系 当我们编写一个较大的软件项目时&#xff0c;通常需要将多个…

js实现图片压缩

创建一个type"file"的input标签&#xff0c;用于文件上传。 <input type"file" name"" id"upload" value"" />通过js实现图片压缩 window.onload function () {const upload document.getElementById("upload…

9.10UEC++生成、销毁actor

BeginPlay&#xff1a; 1.SpawnActor&#xff1a;<模板类>&#xff08;模板::staticclass&#xff08;&#xff09;&#xff0c;FVector const class&#xff0c;FRotation const class&#xff09; 生成一个actor 2.Destory&#xff08;&#xff09;从世界中销毁一个a…

SSM学习笔记-------Spring(一)

SSM学习笔记-------Spring&#xff08;一&#xff09; Spring_day011、课程介绍1.1 为什么要学?1.2 学什么?1.3 怎么学? 2、Spring相关概念2.1 初识Spring2.1.1 Spring家族2.1.2 了解Spring发展史 2.2 Spring系统架构2.2.1 系统架构图2.2.2 课程学习路线 2.3 Spring核心概念…

【zabbix 代理服务器】

目录 一、部署 zabbix 代理服务器1、设置 zabbix 的下载源&#xff0c;安装 zabbix-proxy2、初始化数据库1、创建数据库并指定字符集2、创建 zabbix 数据库用户并授权 3、导入数据库信息4、修改 zabbix-proxy 配置文件5、启动 zabbix-proxy6、在所有主机上配置 hosts 解析7、在…

Maven高级(四)--私服

一.作用 我们所拆分的模块是可以在同一个公司各个项目组之间的项目组之间进行资源共享的&#xff0c;这就需要Maven的私服来实现。 二.场景 两个项目组之间如何基于私服进行资源的共享的呢&#xff1f; 例如A开发了一个模块tlias-utils,B团队进行项目开发&#xff0c;要想使用…

CentOS7 主机万兆网卡配置端口聚合后如何与华为交换机连接并上网

环境: 组装机测试服务器 CentOS 7 CentOS Linux release 7.7.1908 (Core) 网卡1:瑞昱普通千兆板载网卡 网卡2:EB-LINK intel 82599芯片PCI-E X8 10G 光模块千兆单模1310 交换机 HW-S1730S-S48T4S-A Version 5.170 (S1730 V200R021C01SPC200) 光模块千兆单模1310 …

Python学习笔记(十七)————模块相关

目录 &#xff08;1&#xff09;模块 &#xff08;2&#xff09;模块的导入方式 ①import 模块名 ②from 模块名 import 功能名 ③from 模块名 import * ④as定义别名 &#xff08;3&#xff09;自定义模块 &#xff08;4&#xff09;测试模块 &#xff08;1&#xff09…

List移除元素的四种方式

List 移除某个元素 四种方式&#xff1a; 方式一&#xff0c;使用 Iterator &#xff0c;顺序向下&#xff0c;如果找到元素&#xff0c;则使用 remove 方法进行移除。方式二&#xff0c;倒序遍历 List &#xff0c;如果找到元素&#xff0c;则使用 remove 方法进行移除。方式…