【 数据结构:堆(Heap)】大根堆、小根堆、堆的向上调整算法、向下调整算法 及 堆的功能实现!

news2024/11/19 14:48:11

前言

本系列文章【数据结构】默认会使用 C/C++ 进行设计实现!其他语言的实现方式请参照分析设计思路自行实现!


注[1]:文章属于学习总结,相对于课本教材而言,不具有相应顺序性!(可在合集中自行查看是否存在相应文章)!
注[2]:如有问题或想让博主进行思路分析的内容,可在后台私信!


文章目录

  • 前言
  • 完全二叉树的认识
  • 堆的基本认识
  • 堆的性质 及 大小根堆【重要】
  • 堆的结构及其顺序结构(特点)
    • 堆的结构认识
    • 顺序存储结构
  • 向上调整算法
    • 算法基本思路(以小根堆为例):
    • C/C++ 语言代码设计
  • 向下调整算法
    • 算法基本思路(以大根堆为例):
    • C/C++ 语言代码设计


完全二叉树的认识

  • 完全二叉树的定义:对一颗具有n个结点的二叉树按层序编号,如果编号为 i ( 1 <= i <= n)与同样深度的满二叉树中编号为 i 的结点在二叉树中的位置完全相同,则这颗二叉树称为:完全二叉树。
  • 完全二叉树的简单认识(白话描述特点):除了最底层,其他层都是满节点(构成一个满二叉树),最底层一定满足从左到右不含空叶结点的二叉树!

在这里插入图片描述


堆的基本认识

  • 堆(Heap)是计算机科学中一类特殊的数据结构,是最高效的优先级队列。
  • 堆通常是一个可以被看作一棵 完全二叉树 的数组对象。

在这里插入图片描述

上述图片中的第二行式子,描述的就是:堆的特性:堆中某个结点的值总是不大于或不小于其父结点的值!


堆的性质 及 大小根堆【重要】

  • 堆中某个结点的值总是不大于或不小于其父结点的值!

  • 堆总是一棵完全二叉树!

  • 大根堆:即根节点的值最大!

  • 小根堆:即根节点的值最小!

在这里插入图片描述


堆的结构及其顺序结构(特点)

堆的结构认识

  • 在逻辑上,堆的性质之一,堆一定是一个完全二叉树!
  • 在存储结构上,由于完全二叉树的层序”排列特点“,我们一般都是使用数组或其他顺序存储结构来作为存储对象,来模拟堆!

在这里插入图片描述

顺序存储结构

由完全二叉数的图示结构,不难看出,如果按照层序遍历,将其排列成一行,可以形成一个不含空结点(数值)的数组结构!

在这里插入图片描述

如上图所示,将根节点存储在索引值为:0 的位置!(有如下特点!)

若索引为 i 的结点存在左右子结点,则

  • 左子树结点索引:2 * i + 1
  • 右子树结点索引:2 * i + 2

若已知:左 / 右子结点的索引值为:n,则

  • 父节点索引为:(n-1) / 2

向上调整算法

在这里插入图片描述

算法基本思路(以小根堆为例):

  1. 找到不符合堆性质的结点!记为:目标节点!如上图中的:0。
  2. 目标结点与其父节点进行值对比!
  • 若目标结点值 小于父节点的值,则进行父子交换!
  • 若目标结点的值比其父结点的值大,则停止向上调整,此时该树已经是小堆了。

如上图,流程说明:

  • 第一次,0 < 8,交换 0 与 8,此时有原来 8 位置上的就是原来的目标值!
  • 第二次,0 < 4,交换 0 与 4,

    如上图中,目标值 0 一定是向上调整到整棵树的根节点位置!

交换中的索引值确认方式:

  • 若已知:左 / 右子结点的索引值为:n,则:
    • 父节点索引为:(n-1) / 2

C/C++ 语言代码设计

  • 由于 C 语言中没有容器,故我们需要动态申请一块内存作为数组存储我们的数据元素(动态内存申请部分将在后文实现)。
  • C++ 可以直接使用 vector 来作为容器存储数据。
void Swap(DataType* x, DataType* y)
{
	HPDataType tmp = *x;
	*x = *y;
	*y = tmp;
}

/* 向上调整算法 */
// void AdjustUp(vector<DataType>& vec, int idx)	// C++
void AdjustUp(DataType* vec, int idx)
{
	int parent = (idx-1) / 2;	// 记录当前结点的父节点位置!
	while(idx > 0){	
	// 循环条件:目标节点的位置必须合法!
	// 注:当目标节点索引为 1 或 2 时,若发生交换则一定会被调整到 0 处!
		// 小根堆为例:特点:父小于子!
		if( vec[idx] < vec[parent] ){
			Swap(&vec[idx], &vec[parent]);	// 值交换
			idx = parent;			// 更新目标值的索引!
			parent = (idx-1) / 2;	// 更新父节点的索引!
		}else break;		
	}
}


向下调整算法

在这里插入图片描述

算法基本思路(以大根堆为例):

向下调整算法需要满足一个前提:
 若想将其调整为小堆,那么根结点的左右子树必须都为小堆。
 若想将其调整为大堆,那么根结点的左右子树必须都为大堆。

  1. 找到不符合堆性质的结点!记为:目标节点!如上图中的:20。
  2. 目标结点与其较大子节点进行值对比!(大根堆);将目标结点与其较小子节点进行值对比!(小根堆)。
  3. 以大根堆为例,若目标结点值(父) 小于 较大子节点的值,则进行父子交换!

使用堆的向下调整算法,最坏的情况下(即一直需要交换结点),需要循环的次数为:h - 1次(h为树的高度)。而 h = log2(N+1)(N为树的总结点数)。所以堆的向下调整算法的时间复杂度为:O(logN) 。


如上图,流程说明:

  • 第一次,9 < 36,较大值为:36!20 < 36,交换 20 与 36,此时有原来 36 位置上的就是原来的目标值!
  • 第二次,-54 < 10,较大值为:10!20 > 10,调整结束!

交换中的索引值确认方式:

  • 若已知:父结点的索引值为:n,则:
    • 左子树结点索引:2 * n + 1
    • 右子树结点索引:2 * n + 2

C/C++ 语言代码设计

void Swap(DataType* x, DataType* y)
{
	HPDataType tmp = *x;
	*x = *y;
	*y = tmp;
}

/* 向下调整算法:大根堆 */
// void AdjustUp(vector<DataType>& vec, int idx)	// C++
// 参数:size:数组的大小
void AdjustDown(DataType* vec,int size, int idx){
	int child = idx*2+1;	// child 表示子树索引!
	// 此处假设较大值为:左子节点
	while( child < size ){
		// 判断 左右子结点的大小关系
		// 大根堆:选较大的
		// 小根堆:选较小的
		if( child+1 < size && vec[child+1] > vec[child] ) child++;
		if( vec[idx] < vec[child]){
			//将父结点与较大的子结点交换
			Swap(&vec[child], &vec[idx]);
			//继续向下进行调整
			idx= child;
			child = 2 * idx+ 1;
		}else break;
	}
}

待更新!

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

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

相关文章

C++: 继承

学习目标 1.继承的概念及定义 2.基类和派生类对象赋值转换(切片) 3.继承中的作用域(隐藏/重定义) 4.派生类的默认成员函数 5.继承与友元 6.继承与静态成员 7.菱形继承与菱形虚拟继承 8.总结 1.继承的概念及定义 1.1概念 继承: 它允许你创建一个新的类&#xff08;称为子类或派…

小程序uView2.X框架upload组件上传方法总结+避坑

呈现效果: 1.1单图片上传 1.2多图片上传 前言:相信很多人写小程序会用到uView框架,总体感觉还算OK吧,只能这么说,肯定也会遇到图片视频上传,如果用到这个upload组件相信你,肯定遇到各种各样的问题,这是我个人总结的单图片和多图片上传方法. uView2.X框架:uView 2.0 - 全面兼容…

JavaSE学习值之--String类

&#x1f495;"不要同情自己&#xff0c;同情自己是卑劣懦夫的勾当&#xff01;"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;JavaSE学习值之--String类 目录 前言&#xff1a; 一.String类 1.String类的属性 2.字符串的构造 注意&#xf…

基于YOLOv8模型的塑料瓶目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的塑料瓶目标检测系统可用于日常生活中检测与定位塑料瓶目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测算法训练数…

翻译docker官方文档(残缺版)

Build with docker(使用 Docker 技术构建应用程序或系统镜像) Overview (概述) 介绍&#xff08;instruction&#xff09; 层次结构&#xff08;Layers&#xff09; The order of Dockerfile instructions matters. A Docker build consists of a series of ordered build ins…

“高级Vue状态管理 - Vuex的魅力与应用“

目录 引言1. Vuex的简介1.1 什么是Vuex&#xff1f;1.2 Vuex的核心概念 2. Vuex的值获取与改变(综合案例)3. Vuex的异步请求总结 引言 在现代Web开发中&#xff0c;前端应用变得越来越复杂。随着应用规模的扩大和数据流的复杂性增加&#xff0c;有效地管理应用的状态成为了一项…

Android---Synchronized 和 ReentrantLock

Synchronized 基本使用 1. 修饰实例方法 public class SynchronizedMethods{private int sum 0;public synchronized void calculate(){sum sum 1;} } 这种情况下的锁对象是当前实例对象&#xff0c;因此只有同一个实例对象调用此方法才会产生互斥效果&#xff1b;不同的…

APP测试常见功能测试点汇总

1、安装和卸载 安装和卸载是任何一款APP中都属于最基本功能。一旦出错&#xff0c;就属于优先级为紧要的BUG。因此APP的安装和卸载应作为一个测试点多加重视。 1 应用是否可以正常安装&#xff08;命令行安装&#xff1b;豌豆荚&#xff0f;手机助手等第三方软件安装&#xff…

B树、B+树详解

B树 前言   首先&#xff0c;为什么要总结B树、B树的知识呢&#xff1f;最近在学习数据库索引调优相关知识&#xff0c;数据库系统普遍采用B-/Tree作为索引结构&#xff08;例如mysql的InnoDB引擎使用的B树&#xff09;&#xff0c;理解不透彻B树&#xff0c;则无法理解数据…

【通信系列 1 -- GSM 和 LTE】

文章目录 1. LTE(Long Term Evolution)1.1 FDD&TDD简介1.1.1 3G与4G差异1.1.2 频点与band关系1.1.3 band 与运营商的关系 1.2 TDD&FDD区别1.2.1 FDD帧结构1.2.2 TDD帧结构1.2.3 TDD&FDD优势对比1.2.4 TDD缺点 1.3 VoLTE1.3.1 VoLTE 优点11.3.2 VoLTE 优点21.3.3 Vo…

redis-6.2.7 集群安装3主3从

因为资源有限准备了3 台 服务器&#xff0c;先查看防火墙的端口是否开放&#xff0c;如果没有开放先开放端口我使用的 6379 和 6380 这两个端口 所以将这两个端口放开。去redis 官网下载redis 安装包。下载地址 &#xff1a; redis 安装包下载 3. 安装redis 上传上去之后 3 台…

【Java 进阶篇】JavaScript 数据类型详解

JavaScript是一种弱类型脚本语言&#xff0c;具有动态类型。这意味着JavaScript中的变量可以容纳不同类型的数据&#xff0c;并且它们的类型可以在运行时更改。在本文中&#xff0c;我们将深入探讨JavaScript中的数据类型&#xff0c;包括原始数据类型和引用数据类型&#xff0…

TCP/IP(十)TCP的连接管理(七)CLOSE_WAIT和TCP保活机制

一 CLOSE_WAIT探究 CLOSE_WAIT 状态出现在被动关闭方,当收到对端FIN以后回复ACK,但是自身没有发送FIN包之前 ① 服务器出现大量 CLOSE_WAIT 状态的原因有哪些? 1、通常来讲,CLOSE_WAIT状态的持续时间应该很短,正如SYN_RCVD状态2、但是在一些特殊情况下,就会出现大量连接长…

【动态库】Ubuntu 添加动态库的搜索路径

在运行程序时&#xff0c;经常遇到下面这种动态库加载失败的情况&#xff0c;这时往往是系统在动态库的搜索路径下没有找到对应的库文件导致的。 目录 一、使用 LD_LIBRARY_PATH 二、修改 /etc/ld.so.conf 一、使用 LD_LIBRARY_PATH 环境变量 LD_LIBRARY_PATH是动态库的搜索…

【例题】逆波兰表达式求值(图解+代码)

【例题】逆波兰表达式求值(图解代码) 这里写目录标题 【例题】逆波兰表达式求值(图解代码)逆波兰表达式解释优点转换计算代码 题目描述 : 逆波兰表示法是一种将运算符&#xff08;operator&#xff09;写在操作数&#xff08;operand&#xff09;后面的描述程序&#xff08;算式…

1600*A. Linova and Kingdom(DFS优先队列贪心)

Problem - 1336A - Codeforces Linova and Kingdom - 洛谷 解析&#xff1a; 开始认为分情况讨论 k 小于等于叶子结点和大于叶子结点的情况&#xff0c;然后选择深度最深的叶子结点和子孙数量最小的结点&#xff0c;但是发现如果把某一个非叶子结点选取&#xff0c;那么其子孙…

VTP协议

VTP的概念 个人简介 VTP--------------VLAN Trunking protocol VLAN干道协议&#xff08;思科私有协议&#xff09; 同步VLAN编号 VTP&#xff08;Virtual Trunking Protocol&#xff09;是思科&#xff08;Cisco&#xff09;网络设备中的一种协议&#xff0c;用于在交换机之…

Qt QMultiMap

QMultiMap 文章目录 QMultiMap摘要QMultiMapQMultiMap 特点代码示例 关键字&#xff1a; Qt、 QMultiMap、 容器、 键值、 键值重复 摘要 今天在观摩小伙伴撸代码的时候&#xff0c;突然听到了QMultiMap自己使用Qt开发这么就&#xff0c;竟然都不知道&#xff0c;所以趁没…

【环境】我决定半场开香槟!ubuntu20.04 安装 pytorch

还在下载当中&#xff0c;我决定半场开香槟&#xff01;自信稳定安装成功&#xff01; ubuntu20.04 安装 pytorch 硬件及其他环境&#xff1a;win10 ubuntu20.04 3080显卡查找pytorch的版本是最重要的、也是最耽误时间的 PyTorch中torch、torchvision、torchaudio版本对应关…

使用IntelliJ Idea必备的插件!

趁手的工具让开发事半功倍&#xff0c;好用的IDEA插件让效率加倍。 今天给大家分享几个优秀的IDEA插件。 插件安装 首先得知道在IDEA哪安装插件&#xff1f; 点击File---->Settings---->找到Plugins标签&#xff0c;即可搜索想要的插件进行安装了。 现在来看下有哪些值…