数据结构——堆(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.mfbz.cn/a/870353.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV图像滤波(1)双边滤波函数bilateralFilter的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 功能描述 bilateralFilter是图像处理和计算机视觉领域中的一种高级图像滤波技术,特别设计用于在去除噪声的同时保留图像的边缘和细节。相比于传…

网络编程总复习

TCP的创建: 服务器端 : 客户端:

ESP8266用AT指令实现连接MQTT

1准备工作 硬件(ESP8266)连接电脑 硬件已经烧入了MQTT透传固件 2实现连接 2-1(进入AT模式) 打开串口助手发送如下指令 AT 2-2(复位) ATRST 2-3(开启DHCP,自动获取IP&#x…

The Llama 3 Herd of Models.Llama 3 模型论文全文

现代人工智能(AI)系统是由基础模型驱动的。本文提出了一套新的基础模型,称为Llama 3。它是一组语言模型,支持多语言、编码、推理和工具使用。我们最大的模型是一个密集的Transformer,具有405B个参数和多达128K个tokens的上下文窗口。本文对Llama 3进行了广泛的实证评价。我们…

Linux系统上安装Redis

百度网盘: 通过网盘分享的文件:redis_linux 链接: https://pan.baidu.com/s/1ZcECygWA15pQWCuiVdjCtg?pwd8888 提取码: 8888 1.把安装包拖拽到/ruanjian/redis/文件夹中(自己选择) 2.进入压缩包所在文件夹,解压压缩…

深入浅出WebRTC—LossBasedBweV2

WebRTC 同时使用基于丢包的带宽估计算法和基于延迟的带宽估计算法那,能够实现更加全面和准确的带宽评估和控制。基于丢包的带宽估计算法主要依据网络中的丢包情况来动态调整带宽估计,以适应网络状况的变化。本文主要讲解最新 LossBasedBweV2 的实现。 1…

计算机网络实验-RIP配置与分析

前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 一、相关知识 路由信息协议(Routing Information Protocol,RIP)是一种基于距离向量(Distance-Vector&…

python题解

宽度与对齐 输出455、-123、987654,宽度为5,分别左对齐和右对齐 格式 输入格式: 无 输出格式: 输出为整型,空格分隔。每个数的输出占一行 样例 1 输入: 无 复制 输出: 455 455 -123 -123 98…

智慧工地视频汇聚管理平台:打造现代化工程管理的全新视界

一、方案背景 科技高速发展的今天,工地施工已发生翻天覆地的变化,传统工地管理模式很容易造成工地管理混乱、安全事故、数据延迟等问题,人力资源的不足也进一步加剧了监管不到位的局面,严重影响了施工进度质量和安全。 视频监控…

ubuntu安装mysql8.0

文章目录 ubuntu版本安装修改密码取消root跳过密码验证 ubuntu版本 22.04 安装 更新软件包列表 sudo apt update安装 MySQL 8.0 服务器 sudo apt install mysql-server在安装过程中,系统可能会提示您设置 root 用户的密码,请务必牢记您设置的密码。…

从零开始:在Linux系统上创建和管理Conda环境的详细指南【安装教程】

引言 在数据科学和机器学习领域,使用虚拟环境来管理不同项目的依赖是一个常见且重要的实践。Conda是一个强大的包管理和环境管理工具,广泛应用于Python和R的开发环境中。本文将详细介绍如何在Ubuntu系统上从零开始安装和使用Conda,通过创建和…

vscode调试nextjs前端后端程序、nextjs api接口

最近有一个项目使用了nextjs框架,并且使用nextjs同时实现了前后端,由于之前前后端都是分离的,前端的调试可以通过在代码种添加debugger或者直接在浏览器中打断点实现,现在想调试后端接口,前面的方式就不适用了。故研究…

如何查看jvm资源占用情况

如何设置jar的内存 java -XX:MetaspaceSize256M -XX:MaxMetaspaceSize256M -XX:AlwaysPreTouch -XX:ReservedCodeCacheSize128m -XX:InitialCodeCacheSize128m -Xss512k -Xmx2g -Xms2g -XX:UseG1GC -XX:G1HeapRegionSize4M -jar your-application.jar以上配置为堆内存4G jar项…

秋招突击——7/23——百度提前批面试准备和正式面试

文章目录 引言一面准备面试预演一1、讲一下hashcode()和equals()关系2、equals()和有什么区别3、讲一下重载和重写的区别4、讲一下深拷贝、浅拷贝的区别5、讲一下Java异常的基类,运行时异常举几个例子,什么情况下会出现?6、讲一下Java中线程的…

**卷积神经网络典型CNN**

LeNet:最早用于数字识别的CNN AlexNet:2012年ILSVRC比赛冠军,远超第二名的CNN,比LeNet更深,用多层小卷积叠加来替换单个的大卷积 ZF Net:2013ILSVRC冠军 GoogleNet:2014ILSVRC冠军 VGGNet&a…

VLC输出NDI媒体流

目录 1. 下载安装VLC Play 2. 首先在电脑上安装NDI Tools 3. 运行VLC进行输出配置 4. 播放视频 5. 验证 (1)用Studio Monitor验证 (2)用OBS验证 NDI(Network Device Interface)即网络设备接口,是由美国 NewTek 公司开发的免费标准,它可使兼容的视频产品以高质量…

ElasticSearch学习篇15_《检索技术核心20讲》进阶篇之TopK检索

背景 学习极客实践课程《检索技术核心20讲》https://time.geekbang.org/column/article/215243,文档形式记录笔记。 相关问题: ES全文检索是如何进行相关性打分的?ES中计算相关性得分的时机?如何加速TopK检索?三种思路 精准To…

OAK-FFC 分体式相机使用入门介绍

概述 OAK FFC 主控板和多种可选配镜头模组非常适合灵活的搭建您的3D人工智能产品原型。由于镜头是分体式的,因此你可以根据需要测量的距离,自定义深度相机安装基线,并根据你的项目要求(分辨率、快门类型、FPS、光学元件&#xff…

12_TypeScript 模块 以及 模块化封装DB 库

TypeScript 模块 1、模块中暴露方法12、模块中暴露方法23、模块中暴露方法34、封装[上一节的db 库](https://blog.csdn.net/qq_46143850/article/details/140664100)5、TypeScript 命名空间 模块的概念(官方): 关于术语的一点说明&#xff1a…

MFC:以消息为基础的事件驱动系统和消息映射机制

以消息为基础的事件驱动系统和消息映射机制 (1)消息 A.What(什么是消息) 本质是一个数据结构,用于应用程序不同部分之间进行通信和交互 typedef struct tagMSG {HWND hwnd; // 接收该消息的窗口句柄UINT message; // 消息标…