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

news2024/9/21 4:40:38

        树的概念:

        树(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.coloradmin.cn/o/1951286.html

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

相关文章

15 Python常用内置函数——类型转换与类型判断

① 内置函数 bin()、oct()、hex() 用来将整数转换为二进制、八进制和十六进制形式,这3个函数都要求参数必须为整数。 print((bin(168), oct(168), hex(168))) # 把数字转换为二进制串、八进制串、十六进制串内置函数 int() 用来将其他形式的数字转换为整数&#x…

【计算机网络】HTTP协议实验

一:实验目的 1:理解HTTP协议的基本工作原理。 2:使用Wireshark或其他抓包工具捕获并分析HTTP数据包,理解HTTP通信的具体过程。 3:通过分析抓包数据,识别常见的HTTP状态码及其含义。 二:实验仪…

华为OD机试 - 数的分解 (Java/c++/python 2024年C卷D卷)

华为OD机试(C卷D卷)2024真题目录(Java & c & python) 题目描述 给定一个正整数 n,如果能够分解为 m(m > 1)个连续正整数之和,请输出所有分解中,m最小的分解。 如果给定整数无法分…

Linux中的三类读写函数

文件IO和标准IO的区别 遵循标准: 文件IO遵循POSIX标准,主要在类UNIX环境下使用。标准IO遵循ANSI标准,具有更好的可移植性,可以在不同的操作系统上重新编译后运行。可移植性: 文件IO的可移植性相对较差,因为…

从丢失到找回:2024年U盘数据恢复软件全攻略

优盘作为我们日常短时间存储分享数据来说非常方便,毕竟小巧便携。但是也正因为他小巧数据很容易丢失,如果有备份还好,没有备份就麻烦了。但是只要掌握U盘数据恢复方法就可以缩小我们的损失。 1.福foxit昕数据恢复工具 一键直达>>http…

【ESP32 idf 硬件I2C驱动MPU6050获取六轴数值】

目录 I2C介绍配置安装驱动通信创建&删除命令链接容器起始时序写数据读数据结束时序开始命令 mpu6050 硬件i2c驱动代码&调试代码调试 I2C 介绍 介绍部分可以看我写的【ESP32 idf 软件模拟I2C驱动MPU6050实现六轴加速度的获取】,这个是使用软件模拟的I2C时序…

数据结构-C语言-排序(4)

代码位置: test-c-2024: 对C语言习题代码的练习 (gitee.com) 一、前言: 1.1-排序定义: 排序就是将一组杂乱无章的数据按照一定的规律(升序或降序)组织起来。(注:我们这里的排序采用的都为升序) 1.2-排…

找工作准备刷题Day10 回溯算法 (卡尔41期训练营 7.24)

回溯算法今天这几个题目做过,晚上有面试,今天水一水。 第一题:Leetcode77. 组合 题目描述 解题思路 从题目示例来看,k个数是不能重合的,但是题目没有明确说明这一点。 使用回溯算法解决此问题,利用树形…

设计模式-结构型-09-外观模式

文章目录 1、影院管理项目2、外观模式基本介绍4、MyBatis 框架源码分析5、外观模式总结 1、影院管理项目 组建一个家庭影院: DVD 播放器、投影仪、自动屏幕、环绕立体声、爆米花机,要求完成使用家庭影院的功能,其过程为: 直接用…

推荐一个酷炫高逼格的服务器探针的监控工具,免费开源(附源码)

背景 作为一名攻城狮,面对各种服务器内存飙高、CPU猛增、磁盘打满等等服务器问题,可谓是伤透了我们的心。 不仅要开发,还要处理这些问题,大把的时间浪费了,这时候一个好的全面的监控工具尤为重要了。 所以&#xff…

Spring AI (三) 提示词对象Prompt

3.提示词对象Prompt 3.1.Prompt Prompt类的作用是创建结构化提示词, 实现了ModelRequest<List<Message>>接口 Prompt(String contents)&#xff1a;创建一个包含指定内容的Prompt对象。 Prompt(String contents, ChatOptions modelOptions)&#xff1a;创建一个…

Github 2024-07-26 Java开源项目日报 Top10

根据Github Trendings的统计,今日(2024-07-26统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目9HTML项目1TypeScript项目1非开发语言项目1JavaGuide - Java 程序员学习和面试指南 创建周期:2118 天开发语言:Java协议类型:Apache…

【C++】初识C++基础篇·一(命名空间,函数重载,缺省参数,引用);

文章目录 前言1.输入与输出输出输入cin和scanf的对比 2.命名空间2.1namespace存在的意义2.2namespace的使用3.缺省参数4.函数重载重载函数的调用规则 5.引用 前言 我们先通过一段简单的代码来拉开C的序幕&#xff1b; //text.cpp #include<iostream> #include<stdio…

C++知识点总结:3.C++引用(自用)

C引用 1. 引用定义2. 引用的本质3. 引用和指针的不同之处补充指针常量和常量指针 4. 引用不能指代临时变量5. const引用&#xff08;常引用&#xff09;可以绑定临时数据6. const引用与转换类型 引用&#xff1a; [1]C语言中文网 [2]偶尔e网事,【C基础之二】常量指针和指针常量…

学习记录:ESP32控制舵机 FREERTOS BLE

控制舵机 PWM信号 PWM信号是一种周期性变化的方波信号&#xff0c;它有两个关键参数&#xff1a; 周期&#xff08;Period&#xff09;&#xff1a;一个完整的PWM信号的时间长度&#xff0c;通常用秒&#xff08;s&#xff09;或毫秒&#xff08;ms&#xff09;表示。占空比…

MQ消息队列+Lua 脚本实现异步处理下单流程

具体实现和代码可参考我以前做过的笔记&#xff1a;《黑马点评》异步秒杀优化|消息队列 回顾一下下单流程&#xff1a; 用户发起请求 会先请求Nginx,Nginx反向代理到Tomcat&#xff0c;而Tomcat中的程序&#xff0c;会进行串行工作&#xff0c; 分为以下几个操作&#xff1…

昇思25天学习打卡营第25天|基于 MindSpore 实现 BERT 对话情绪识别

基于 MindSpore 实现 BERT 对话情绪识别 模型概述 BERT&#xff08;双向编码器表征量&#xff09;是Google于2018年发布的一种先进语言模型&#xff0c;基于Transformer架构&#xff0c;具备双向上下文理解功能。BERT的预训练方法创新性地结合了两种任务&#xff1a; Masked …

高级网页爬虫开发:Scrapy和BeautifulSoup的深度整合

引言 在互联网时代&#xff0c;数据的价值日益凸显。网页爬虫作为一种自动化获取网页内容的工具&#xff0c;广泛应用于数据挖掘、市场分析、内容聚合等领域。Scrapy是一个强大的网页爬虫框架&#xff0c;而BeautifulSoup则是一个灵活的HTML和XML文档解析库。本文将探讨如何将…

凸优化笔记-基本概念

原文 文章目录 最小二乘问题 仿射affine hullaffine dimension 凸集锥集超平面和半空间单纯形整半定锥保凸性的操作透视函数 凸函数的条件1阶判定条件2阶判定条件 Epigraph 外图 m i n i m i z e f 0 ( x ) minimize\ \ \ f_0(x) minimize f0​(x) s u b j e c t t o f i ( …

Python 爬虫入门(一):从零开始学爬虫 「详细介绍」

Python 爬虫入门&#xff08;一&#xff09;&#xff1a;从零开始学爬虫 「详细介绍」 前言1.爬虫概念1.1 什么是爬虫&#xff1f;1.2 爬虫的工作原理 2. HTTP 简述2.1 什么是 HTTP&#xff1f;2.2 HTTP 请求2.3 HTTP 响应2.4 常见的 HTTP 方法 3. 网页的组成3.1 HTML3.1.1 HTM…