树形结构——堆的构建

news2024/11/18 5:51:35

  在学习完我们的树形结构之后我们再来使用树形结构的思想构建一个堆。使用堆可以对我们的数据进行排序,并且堆排序的效率要远优于我们之前学习过的冒泡排序。下面我们来逐步实现堆这个数据结构。

  在构建堆之前我们需要先介绍以下我们树形结构构建的两种形式:顺序存储和链式存储。顺序存储的形式也就是使用类似于数组的形式进行数据的存储。针对于树形结构的特点我们可以很容易的发现每一个父节点和孩子节点之间都有一定的关系 parent=(child-1)/2 或者使用儿子节点进行表示:child=parent*2+1表示左孩子,child=parent*2+1+1表示右孩子,测试效果如下:

   我们就可以使用上面的特点在数组当中将各节点当中的数据存储进去。

  我们可以根据上面的父节点和孩子节点之间的相互转换进行指定数据的存储。 但是我们会发现使用顺序存储的形式存储树型结构只适合存储满二叉树。否则就会出现大量的空白造成存储空间的浪费,例如:

  但是对于数据的排序我们使用顺序存储的形式是最合适的,我们只需要构建一个对即可,并且我们构建的堆在定义上是满堆状态。因此我们在本次博客当中主要使用顺序表进行构建堆。(构建链式的二叉树我们将会在下一次博客当中进行详细的讲解。)

  那么我们闲话少说,直接来到我们对于堆的介绍。

  堆有两种形似:大堆和小堆。大堆的定义是:我们父节点当中的数据全部都大于子节点当中的数据。所以我们堆顶的数据是所有要排序的数据当中最大的元素。

   另一种是小堆,和我们的大堆进行类比我们可以猜出小堆的概念是:我们任意一个父节点当中的数据都小于子节点。我们小堆堆当中的元素是我们所有数据当中最小的那个。

  我们可以根据上面的思路使用大堆每次选出数据当中最大的元素使得数组有序。接下来正式开始堆代码的编写。

  由于我们使用的是顺序存储的形式构建的树形结构,(在实际存储的结构形式还是顺序表)所以我们可以先构建一个顺序表之后在进行相应的修改即可。所示的代码如下:

  之后构建一个初始化顺序表的函数:

   该部分代码和我们之前一直使用的顺序表的构建和初始化完全相同,在此就不做过多的解释了。详情请回顾顺序表的博客内容。

  在初始化顺序表之后我们就可以书写向堆中输入数据的函数了。

  首先要想向数组当中插入数据那么我们要做的第一步就是检查数组是否已满,如果入组已满我们就需要进行扩容。之后将我们的数据给到数组指定的位置即可。但是我们要想使用堆进行数据的排序就必须保证我们的堆是一个大堆或者小堆。所以我们就需要构建一个向上调整函数进行数据顺序的调整。也就是我们上面的Adjustup函数。 

   我们会发现当我们数组当中只存在一个数据的时候不需要进行调整,那么我们只需要在插入第二个数据的时候进行调整即可。

  我们可以接着进行测试,插入第三个数据:

  我们只需要每插入一个数据都对数组进行向上调整,我们构建的堆就一定是大堆。我们先来实现向上调整部分的代码:

   因为我们每一次插入数据都会进行一次向上调整所以我们构建出来的堆一定为大堆。所以我们新插入的数据只需要和我们最近的父节点进行比较如果,子节点当中的数据大于父节点当中的数据就进行交换,否则就不进行交换,当我们不进行交换循环也就结束。当我们和根节点交换之后循环也照常结束。根据上述思路我们可以编写出上述的代码。我们可以测试以下,尝试向数组当中插入一些数据:

   将我们上述的数组中的元素改写成树形结构的形式验证我们数组当中的元素为大堆:

  那么我们向堆中插入数据的函数也就书写完成了。

  既然有插入数据的函数那么一定有删除数据的函数,接下来我们就来构建删除堆中数据的函数。首先我们需要思考的是: 在堆中我们想要删除数据究竟应该删除什么样的数据呢?删除删除什么样的数据才有意义呢?假如我们删除堆低的数据,就像是我们上面创建的堆的表示一样,删除24并没有什么实际意义,24既不是最小的数据也不是最大的数据。我们甚至不知道24在数组当中的地位是怎么样的。但是假如我们想要删除的数据是堆顶的数据的时候,因为我们创建的是一个大堆或者小堆,那么堆顶的数据就是数组当中最大的或者是最小的。我们可以将这个数据删除并返回,之后我们再将我们剩下的数据按照对的形式排列。那么我们就可以继续选择出最大的或者最小的元素了。我们通过代码来了解一下该部分函数的编写:

   和我们所有的删除函数一样,我们进行数据删除操作之前需要先对数组进行判空操作,如果数组当中不存在数据就对数据进行删除。如果我们数组当中只存在一个数据的时候我们就可以直接将我们数组当中的元素删除,不需要再进行元素的调整操作。

  就像是上面我们进行的操作一样,将我们交换之后的堆顶的元素和孩子节点进行比较,并和最大的孩子节点进行交换。最后调整到合适的位置即可。调整之后依旧是一个新的大堆。我们还可以重复上述步骤进行数据的依次选择。最后得到有序的数据列。由于我们上面的的操作是从上到下进行数据的调整的所以我们需要设计一个向下调整函数进行,完成我们上面的操作。代码如下:

 

  之后我们依旧可以对我们编写的代码进行检测:

   我们通过调试可以发现通过三个删除操作已经将我们最大的三个数据调整到我们数组的最后三个位置上面了,并且我们数组的大小由原本的10变更为7。我们可以将剩余的数据构建一个堆的结构,观察其是否满足大堆的结构特点:

  在构建完我们最主要的插入数据的函数和删除数据的函数之后,只剩下一些便于我们使用的函数了,这些函数的编写内容很简单。

    对堆进行判空的函数:

  我们可以使用这个函数和我们的删除函数相结合,如果堆为空就不进行删除操作。

  返回堆顶元素的函数:

   

  我们可以使用这个函数得到堆顶的最大或者最小的数据,之后再将我们堆顶的元素删除即可。

 判断堆的大小的函数:

堆的销毁函数:

 

  当我们使用完向内存申请的空间之后我们必须将这些空间返回给系统,避免内存泄露的问题。之后我们使用我们上面编写的代码对一些数据进行打印并输出吧!

   我们会发现我们只需要将我们之前编写的函数结合起来,使用一个简单的for循环便可实现对数据的排序操作了。

  以上我们创建了一个堆(逻辑结构是一颗二叉树)进行数据的排序。在简单的学习完堆的工作原理之后我们将在下一次的博客当中比较堆和冒泡排序函数,方便我们感受堆排序的优点。那么感谢您的观看,祝您天天开心。

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

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

相关文章

掌握这些GitHub搜索技巧,你的开发效率将翻倍!

作为开发it行业一员,学习借鉴他人项目是很有必要的,所以我们一般都会从github或者 Gitee 上面去参考借鉴他人的项目来学习增加自己的项目经验 但是一般我还是在github上看项目比较多,毕竟人家实力项目量摆在那里 ,但是国内访问gi…

Spring Cloud的那些组件和功能,get到了吗

Spring Cloud 是 Spring 技术栈生态很重要的一部分,面向大型网站服务端的开发和架构设计,它以 Spring/SpringBoot 为基础,提供的一系列组件规范和具体实现。 一、概述 Spring Cloud 提供了用于更快速构建分布式系统的基础规范(例…

“深入”理解字节对齐

文章目录 前言思考查阅资料[Byte alignment and ordering](https://www.eventhelix.com/embedded/byte-alignment-and-ordering/)Byte Alignment RestrictionsWhy Restrict Byte Alignment?Compiler Byte PaddingUser Defined StructureActual Structure Definition Used By t…

使用SaleSmartly自动化流程的 5 个原因

想象一下,如果您可以采用智能数字解决方案来减轻团队和公司的手动和重复业务流程负担。它可以帮助您节省时间、提高公司的底线、消除冗余并增强数据管理。SaleSmartly(ss客服)就是这样。 通过利用自动化的力量,SaleSmartly&#x…

牛客网专项练习Pytnon分析库(一)

1.提取出a和b两个数组中的公共项,可以使用numpy库中的哪个函数(A)。 A.np.intersect1d(a,b) B.np.setdiff1d(a,b) C.np.where(a b) D.np.lexsort((a,b)) 解析: A选项,np.intersect1d用来获取数组a和数组b之间的公共项&…

MySQL遇到过死锁问题吗,你是如何解决的?

MySQL遇到过死锁问题吗,你是如何解决的? 问题解析 死锁,就是两个或者两个以上的线程在执行过程中,去争夺同一个共享资源导致互相等待的现象。 在没有外部干预的情况下,线程会一直处于阻塞状态,无法往下执行…

理解FPGA的基础知识——逻辑电路

FPGA (Field Programmable Gate Aray,现场可编程门阵列)是一种可通过重新编程来实现用户所需逻辑电路的半导体器件。为了便于大家理解FPGA的设计和结构,我们先来简要介绍一些逻辑电路的基础知识。 1.逻辑代数 逻辑代数中的变量称为逻辑变量,用大写字母表…

Arduino ESP32 ESP-Rainmaker点灯示例

Arduino ESP32 ESP-Rainmaker点灯示例 📌基于ESP-IDF工程相关篇《ESP32 ESP-Rainmaker 本地点灯控制Demo测试》🎈原项目地址:https://github.com/espressif/esp-rainmaker🔖本次所测试的项目示例工程:\esp-rainmaker—…

backtrader的cs功能介绍

cs框架的优点和缺点 优点和ts一样,就是速度非常快缺点有好几个:必须使用根据过去一定天数计算因子值,持有一定天数之后再平衡的模式;必须使用连续的数据,如果是期货期权等需要合成连续数据。资金不足的时候不会拒单。cs框架使用方法 设计理念 计算因子由用户进行计算,因…

用科技创造未来!流辰信息技术助您实现高效办公

随着社会的迅猛发展,科技的力量无处不见。它正在悄悄地改变整个社会,让人类变得进步和文明,让生活变得便捷和高效。在办公自动化强劲发展的今天,流辰信息技术让通信业、电网、汽车、物流等领域的企业实现了高效办公,数…

工具及方法 - 安装播放器pot player

官网下载: potplayer.daum.net 可能国内访问有问题,还有一个网站: Global Potplayer 或者为了纯净安全些,找下国外可下载网站: PotPlayer 230407 / 230504 Beta Free Download - VideoHelp 下载后安装即可&#xff…

红蜻蜓利用档案数字化管理,实现业务管理降本增效

在数字化大背景下,红蜻蜓积极拥抱数字化档案,全面优化档案管理成本,保证组织档案安全可信,助力企业业务高质量发展。 关于红蜻蜓 红蜻蜓,创始于1995年,是一家多品牌、多品类的时尚鞋履品牌运营商&#xf…

欧科云链OKLink:2023年4月安全事件盘点

一、基本信息 2023年4月安全事件共造约6000万美金的损失,与上个月相比,损失金额有所降落,但安全事件数量依旧不减。其中,Yearn Finance因参数配置错误,导致了1000多万美金的损失。同时,有一些已经出现过的…

【剧前爆米花--爪哇岛寻宝】TCP/IP协议以及在网络传输过程中的封装与分用

作者:困了电视剧 专栏:《JavaEE初阶》 文章分布:这是一篇关于网络初识的文章,在这篇文章中讲解了TCP/IP协议的主要内容和砸在网络传输过程中的封装和分用,希望对你有所帮助! 目录 TCP/IP五层模型 应用层…

渲染和不渲染的区别是什么?

随着计算机技术日新月异不断发展,电脑合成技术图像技术也日益成熟。在三维制作中,经常会提到一个词“渲染”,很多没有接触三维制作的朋友可能不是太清楚它究竟是什么,图像制作后,渲染和不渲染的区别是什么,…

【Admin后台管理】Geodjango后台显示地图并加载空间字段

原文作者:我辈李想 版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、djangoadmin二、geodjangoadmin三、报错处理 前言 在前面的博客中,我们已经介绍了Geodjango的环境搭建和数据库操作&…

网易云音乐开发--前后端交互

前后端交互 首先启动服务器 1. 根目录下执行: npm start 2. 服务器地址: http://localhost:3000 3. 示例: http://localhost:3000/banner 测试接口能不能用 发起请求 看接口说明,在wx的load函数中发起请求 请求成功 封装请求功能函数 …

Django框架之ORM和模型属性

Django对很多数据库都有支持,为这些数据库提供了统一的调用API。可以根据不同的业务需求,选择配置不同的数据库。本篇文章主要介绍ORM和模型属性。 ORM ORM全称Object Relational Mapping,即对象关系映射,是在pymysq之上又进行了…

JAVAWeb11-服务器渲染技术 -JSP-01-JSP基础

1. 现状 1、JSP 使用情况 2、Thymeleaf 使用情况, 通常和 SpringBoot 结合(也会讲) 3、Vue 使用情况 2. 学 JSP 前,老师要说的几句话 目前主流的技术是 前后端分离 (比如: Spring Boot Vue/React), 我们会讲的.[看一下]JSP 技术使用在逐渐减少&#xff…

06 - 4 微内核架构

什么是微内核架构 定义 微内核 核心功能资源封装 插件 可插拔 系统核心 资源封装 硬件接口系统资源访问接口环境/上下文(context)访问接口系统事件接口 定义插件规范 使用场景规则条件 核心功能 支持系统运作的最小功能集 职责分离 通用流程由核心…