数据结构——堆(C语言版)

        树的概念:

        树(Tree)是一种抽象数据结构,它由节点(node)的集合组成,这些节点通过边相连,把

节点集合按照逻辑顺序抽象成图像,看起来就像一个倒挂着的树,也就是说数据结构中的树是根成朝上,叶子朝下。

        树形结构中,⼦树之间不能有交集,否则就不是树形结构 ,就不能称之为树

        ⾮树形结构:        

        像上图,子节点与子节点会相交,这种就不能称之为树。

        树的专业术语

                ⽗结点/双亲结点:若⼀个结点含有⼦结点,则这个结点称为其⼦结点的⽗结点
                ⼦结点/孩⼦结点:⼀个结点含有的⼦树的根结点称为该结点的⼦结点;
 
                结点的度:⼀个结点有⼏个孩⼦,他的度就是多少;
                叶⼦结点/终端结点:度为 0 的结点称为叶结点; 
                分⽀结点/⾮终端结点:度不为 0 的结点;
 
                兄弟结点:具有相同⽗结点的结点互称为兄弟结点(亲兄弟);
                树的高度或深度:树中结点的最⼤层次; 
                结点的祖先:从根到该结点所经分⽀上的所有结点;
                路径:⼀条从树中任意节点出发,沿⽗节点-⼦节点连接,达到任意节点的序列;
                ⼦孙:以某结点为根的⼦树中任⼀结点都称为该结点的⼦孙。
                森林:由 m(m>0) 棵互不相交的树的集合称为森林;

二叉树

        二叉树的概念:

        在树形结构中,我们最常⽤的就是⼆叉树,⼀棵⼆叉树是结点的⼀个有限集合,该集合由⼀个根结点 加上两棵别称为左⼦树和右⼦树的⼆叉树组成或者为空。

        

        二叉树的特征:

                从上图可以看出⼆叉树不存在度⼤于 2 的结点 ,并且⼆叉树的⼦树有左右之分,次序不能颠倒,因此,二叉树又是一个有序树。

        

        以上均为二叉树可能出现的情况。

                满二叉树与完全二叉树

                        满二叉树:

        满二叉树是一种特殊的完全二叉树。⼀个⼆叉树,如果每⼀个层的结点数都达到最⼤值,则这个⼆叉树就是满⼆叉树。也就是说,如果⼀ 个⼆叉树的层数为 K ,且结点总数是 2 k − 1 ,则它就是满⼆叉树。

        从上图可以看出,满二叉树属于一个等比数列,通过等比数列求和公式可以计算出满二叉树的节点总数。    

                        完全二叉树

        完全二叉树(Complete Binary Tree)是一种特殊的二叉树,其所有节点按照从上到下、从左到右的顺序填充,除了最后一层可能不是满的,其他所有层都必须是满的

        根据上图示例,只有左边是完全二叉树,而右边不是,因为完全二叉树要保证k-1层是满的,而第l层要保证顺序必须一次按照从左到右,不能中间断开。同时也可以推断出完全二叉树的节点范围为[2^(h-1),2^h-1].

        2^(h-1)  是高度为 ( h ) 的二叉树最少的节点数。它表示二叉树的最底层可能是单侧排列的最小节点数,即最小深度。

         2^h - 1  是高度为 ( h ) 的二叉树的最大节点数。它表示如果二叉树是满二叉树,所有层都是满的情况下的节点数。

                        二叉树的性质:
        若规定根结点的层数为 1 ,则⼀棵⾮空⼆叉树的第i层上最多有 2^(k−1) 个结点
        
        
        
        
        若规定根结点的层数为 1 ,则深度为 h 的⼆叉树的最⼤结点数是 2^h-1(最大节点数情况为满二叉树,上图证明过了)
        
        若规定根结点的层数为 1 ,具有 n 个结点的满⼆叉树的深度 ( log 以2为底, n+1 为对数)
h = log (n + 1)

                        二叉树的存储结构:

        ⼆叉树⼀般可以使⽤两种结构存储,⼀种顺序结构,⼀种链式结构,而在这篇文章,小编主要说的是顺序存储。

                                顺序存储:
        顺序结构存储就是使⽤数组来存储,⼀般使⽤数组只适合表⽰完全⼆叉树。

        

        从上图可以看出,二叉树使用顺序存储时,在物理结构上就是一个数组,而拆解成逻辑结构就是一个二叉树,而用顺序表存储二叉树时,只适用于完成二叉树与满二叉树,因为不是完全⼆叉树会有空间的浪费,完全⼆叉树更适合使⽤顺序结构存储。现实中我们通常把堆(⼀种⼆叉树)使⽤顺序结构的数组来存储,需要注意的是这⾥的堆和操作系统 虚拟进程地址空间中的堆是两回事,⼀个是数据结构,⼀个是操作系统中管理内存的⼀块区域分段。

    用堆实现二叉树

            小根堆:

        从上图可以发现,在堆顶(数组下标为0)的位置中存放的数据,是这个堆中最小的值,并且堆中某个结点的值总是不⼩于其⽗结点的值,我们将这种堆称之为小根堆。

            大根堆:

                

        从上图可以发现,在堆顶(数组下标为0)的位置中存放的数据,是这个堆中最大的值,并且堆中某个结点的值总是不大于其⽗结点的值,我们将这种堆称之为大根堆。

            堆的实现

                堆的结构:

        

        根据上图结构可以得知,堆的底层为一个顺序表,那么顺序表里存的数值不一定是整型,所以这里用typedef命名变量类型,这样后期改的话也方便,接着就是定义一个size用来存储堆的有效数据,capaticy用来存储堆的容量。

                初始化堆:

                入堆

        第一步:先进行断言,判断传入是指针是否为NULL。

        第二步:再次判断size是否等于capaticy,如果等于就进行扩容。

       第三步:接着将数组a的size(尾部)下标位置插入x值,并将size++指向有效数值的下一个位置。最后通过向上调整算法,维护堆里的数据。

                向上调整算法:

        假设这里假设此时为大堆,大堆堆顶为最大值,其父节点都不会小于它们的孩子节点。

        这里先定义一个Swap(交换函数),为后续的交换做准备。向上调整函数定义了两个参数,第一个为指向堆的指针,第二个为child(孩子)位置。这里需要知道一个公式,父亲节点位置=(孩子节点位置-1)/2。

        第一步:定义一个parent变量,用于保存父亲节点位置

        第二步创建while循环,因为是向上调整,所以起始位置会在数组末尾,当孩子节点为0的时候表示已经达到了堆顶的位置则就不需要进行调整,循环结束。

        第三步:在循环里创建一个if语句,如果父亲节点的值小于孩子节点,那么就进行向上交换,孩子变父亲,父亲变孩子,然后将父亲位置赋值给孩子,继续向上找父亲节点位置进行循环判断是否交换,如果不需要交换(父亲节点>孩子节点)就直接退出循环。

                出堆

        出堆一般是在堆顶进行弹出数据,因为要么是取最大值要么是取最小值,在堆底出堆并没有任何的意义所在。

        第一步:先判断传进来的指针是否为NULL,并且保证堆里有数据才能进行出堆操作。

        第二步:交换堆顶和堆底的值,并将堆的有效数据位置size--。

        第三步:进行向下调整。

                向下调整算法:

假设这里假设此时为大堆,大堆堆顶为最大值,其父节点都不会小于它们的孩子节点。

        向下调整函数定义了三个参数,第一个为指向堆的指针,第二个为parent(父亲)位置,第三个为堆的长度。

        第一步:先定义child(孩子)变量,这里只需要计算出左孩子的位置,根据数组的特性,数组为一块连续的内存地址,所以计算出左孩子的位置再加一就是右孩子的位置。根据公式:父亲节点位置=(孩子节点位置-1)/2,得出左孩子位置=parent*2+1。

        第二步:创建whil循环,当孩子值大于size长度说明循环走完了一个堆则直接退出循环否则会下标越界。

        第三步:先建立第一个if语句,先判断chid+1是否小于size,为了确保数组不会越界访问接再判断左右孩子的值哪一个更大,因为弹出了最大的值,所以要将第二大的值变成堆顶数据。如果右孩子的值比左边孩子大那么就++child。

        第四步:建立第二个if语句如果此时孩子节点的值会大于我的父亲节点,那么就交换孩子节点与父亲节点,并重新将child(孩子)位置赋值给parent(父亲),孩子位置再次等于parent*2+1,向下进行循环调整。

        

                取堆顶数据

        

                销毁堆

       

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

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

相关文章

使用C#手搓Word插件

WordTools主要功能介绍 编码语言:C#【VSTO】 1、选择 1.1、表格 作用:全选文档中的表格; 1.2、表头 作用:全选文档所有表格的表头【第一行】; 1.3、表正文 全选文档中所有表格的除表头部分【除第一行部分】 1.…

java面向对象进阶篇--《多态》

目录 一、前言 二、认识多态 方法重写(Override): 方法重载(Overload): 示例: Person类(父类) Administrator(子类) Student(子…

docker搭建ES 8.14 集群

参考:【docker搭建es8集群kibana】_docker 安装生产级 es 8.14 集群-CSDN博客 1、之前已搭建一台单机版的dockerES集群 参见 Elasticsearch docker 安装_docker 安装es8.14.3-CSDN博客 2、现在需要重新搭建为docker ES集群 准备新搭建3个点 一、准备工作 提前开…

构建网络安全之盾:应对“微软蓝屏”教训的全面策略

✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…

深度学习模型Transformer结构

Transformer结构是一种基于自注意力(Self-Attention)机制的深度学习模型,最初由Vaswani等人在2017年的论文《Attention Is All You Need》中提出,用于解决自然语言处理(NLP)领域的任务,如机器翻…

MySQL --- 库的操作

一、创建数据库 create database [ if not exists ] 数据库名; // []中的为可选项 在创建库时,也可以指定数据库采用的字符集(character set)和数据库字符集的校验规则(collate) (当我们创建数据库没有指定字符集和校验规则时,系统使用默认字符集&#x…

【复习】软件工程

软件危机是指在计算机软件的开发和维护过程中所遇到的一系列严重问题。 典型表现: 开发成本和进度的估计常常很不准确 用户对已完成的软件系统不满意,闭门造车 软件质量(quality)不可靠 软件常常是不可维护的 软件产品供不应…

css技巧混合模式

看上面这个神奇的效果,文字在黑色背景里面显示为白色,而在白色的背景里面显示为黑色,这就是文字智能适配背景。 看到这样的需求,大多数人第一时间想到的是,文字元素有两个,是完全重叠的两层,一…

Facebook在内容创作中的新策略与机会

随着社交媒体的不断发展,内容创作已经成为了平台吸引和留住用户的核心竞争力。Facebook作为全球最大的社交平台之一,不断调整和优化其内容创作策略,以适应用户需求的变化和技术的进步。本文将深入探讨Facebook在内容创作中的新策略与机会&…

考研复习7月进度严重滞后?

宇哥说:来不及了! 因为基础30讲和强化36讲,加起来已经快300小时了。 所以,必须换个思路: 不看课行吗? 大多数人7月的情况是这样的: 1. 听完线代,高数知识点忘得差不多了&#xf…

JMeter接口测试-3.断言及参数化测试

1. 断言 JMeter官方断言(Assertion)的定义 用于检查测试中得到的响应数据是否符合预期,用于保证测试过程中的数据交互与预期一致 断言的目的: 一个取样器可以添加多个不同形式的断言,根据你的检查需求来添加相应的…

自动驾驶系列—智能巡航辅助功能中的路口通行功能介绍

自动驾驶系列—智能巡航辅助功能中的车道中央保持功能介绍 自动驾驶系列—智能巡航辅助功能中的车道变换功能介绍 自动驾驶系列—智能巡航辅助功能中的横向避让功能介绍 自动驾驶系列—智能巡航辅助功能中的路口通行功能介绍 文章目录 2. 功能定义3. 功能原理4. 传感器架构5. 实…

Java语言程序设计基础篇_编程练习题**15.18(使用鼠标来移动一个矩形)

**15.18(使用鼠标来移动一个矩形) 请编写一个程序显示一个矩形。可以使用鼠标单击矩形内部并且拖动(即按住鼠标移动)矩形到鼠标的位置。鼠标点成为矩形的中央习题思路: 新建一个面板Pane(),新建一个Rectangle() 为Rectangle注册…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第三十九章 Linux MISC驱动

i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

web每日一练

每日一题 每天一题罢了。。 ctfshow内部赛签到 扫到备份文件 login.php <?php function check($arr){ if(preg_match("/load|and|or|\||\&|select|union|\|| |\\\|,|sleep|ascii/i",$arr)){echo "<script>alert(bad hacker!)</script>&q…

微服务和VUE入门教程(16): zuul 熔断

1. 前言 在开发工程中&#xff0c;我们发现当一个微服务挂掉之后&#xff0c;如果我们访问此微服务的接口&#xff0c;zuul也会挂掉。因为zuul负责分配请求&#xff0c;当目标微服务挂掉之后&#xff0c;zuul便找不到目标微服务&#xff0c;因为我们需要设置一个熔断&#xff0…

电机调速控制模块说明文档

电机调速控制模块说明文档 图1-1总览图片 概述本电机控制模块是用于精确控制直流无刷电机运行、以及转速的关键组件&#xff0c;它能够实现对电机的启动、停止、调速、转向等操作&#xff0c;并提供多种保护功能&#xff0c;以确保电机的安全稳定运行。 驱动方式&#xff1a;…

如何学习Python:糙快猛的大数据之路(学习地图)

在这个AI和大数据主宰的时代,Python无疑是最炙手可热的编程语言之一。无论你是想转行还是提升技能,学习Python都是一个明智之选。但是,该如何开始呢?今天,让我们聊聊"糙快猛"的Python学习之道。 什么是"糙快猛"学习法? "糙快猛"学习法,顾名思…

OpenGL笔记十四之GLM数学库的配置与使用

OpenGL笔记十四之GLM数学库的配置与使用 —— 2024-07-20 中午 bilibili赵新政老师的教程看后笔记 code review! 文章目录 OpenGL笔记十四之GLM数学库的配置与使用1.旋转变换运行效果2.平移变换运行效果3.缩放变换运行效果4.复合变换&#xff1a;先旋转 再平移运行效果5.复合…

OpenTeleVision复现及机器人迁移

相关信息 标题 Open-TeleVision: Teleoperation with Immersive Active Visual Feedback作者 Xuxin Cheng1 Jialong Li1 Shiqi Yang1 Ge Yang2 Xiaolong Wang1 UC San Diego1 MIT2主页 https://robot-tv.github.io/链接 https://robot-tv.github.io/resources/television.pdf代…