当前位置: 首页 > news >正文

100.【C语言】数据结构之二叉树的堆实现(顺序结构) 1

目录

1.顺序结构

2.示意图

 ​编辑

从物理结构还原为逻辑结构的方法

3.父子节点编号的规律

4.顺序存储的前提条件

5.堆的简介

堆的定义

堆的两个重要性质

小根堆和大根堆 

6.堆的插入

7.堆的实现及操作堆的函数

堆的结构体定义

堆初始化函数HeapInit

堆插入元素函数HeapPush

堆向上调整函数AdjustUp

写法1

写法2

写法3

提问

向上调整的前提

测试堆插入函数


1.顺序结构

存储二叉树的两种结构:一种顺序结构,一种链式结构本文讲顺序结构


2.示意图

 4311a3c884de4d0caec5b45ef6aa9c66.png

上方图中的数字0~6代表各个节点的编号 

逻辑结构:方便人理解的结构 物理结构:实实在在存储的结构

可见顺序结构的底层是用数组(连续)存储的

从物理结构还原为逻辑结构的方法

对于满二叉树而言,

第一层有一个节点,第二层有两个节点,第一层有四个节点......

则可按层拆分

4f110e1b52564653809e45ad5700440e.png

再组合

aac1aff2adc14578a3eb1be99060ba31.png

加上线

68aacacb93554bda9e40b9e6ea2aa5ee.png

 对于完全二叉树而言,做法和上述类似,不再赘述

3.父子节点编号的规律

比如求F的父节点,如果画图则太慢,其实可以看出规律

F编号为5,其父节点C编号为2;E编号为4,其父节点B编号为1;

发现eq?%5B%5Cfrac%7B5-1%7D%7B2%7D%5D%3D2%2C%5B%5Cfrac%7B4-1%7D%7B2%7D%5D%3D%5B1.5%5D%3D1(注:eq?%5Bx%5D为高斯函数,又称向下取整函数)

★★★求父节点b编号的公式:eq?%5B%5Cfrac%7Bchild-1%7D%7B2%7D%5D%3Dfather

在C语言中为father = (child-1)/2;father获得表达式的商

如果给出父节点的编号,求左孩子和右孩子的编号

父节点C编号为2,则左孩子F的编号为2*2+1,则右孩子G的编号为2*2+2

★★★求孩子节点编号的公式:左孩子:eq?2*father+1  右孩子:eq?2*father+2

4.顺序存储的前提条件

结论:完全二叉树(含满二叉树)适合用顺序存储

25f932f64b0c4f89a726508dbdac504f.png

如果非完全二叉树,存储会浪费空间

5.堆的简介

堆的定义

如果有一个关键码的集合eq?K%20%3D%20%5C%7B%20k_0%2Ck_1%2Ck_2%2C...%2Ck_%7Bn-1%7D%5C%7D,把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:eq?K_i%20%3C%3D%20K_%7B2*i+1%7Deq?K_i%3C%3D%20K_%7B2*i+2%7D%20%28K_i%20%3E%3D%20K_%7B2*i+1%7D%29eq?K_i%20%3E%3D%20K_%7B2*i+2%7D(i=0,1,2,3,..,n)则称为小堆(或大堆)

堆的两个重要性质

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

  • 总是一棵完全二叉树

小根堆和大根堆 

小根堆:树中所有的父节点的值都小于或等于孩子节点的值

大根堆:树中所有的父节点的值都大于或等于孩子节点的值

如果树中所有的父节点的值都等于孩子节点的值,则既为小根堆又为大根堆

注:等定义中并没有规定左孩子和右节点的值的大小关系,因此堆不一定有序

6.堆的插入

由堆的简介可知:堆是一个完全二叉树,因此可以用顺序结构实现

以下方大根堆为例

5516201b19fc4ff4ba832151b1735e7f.jpeg

现要尾插数字20,由存储结构可以看出:空间不够,要扩容

586ea01b4e95478fadf61f4dbb53bc8f.jpeg

插入20前,找其父节点(eq?%5B%5Cfrac%7Bchild-1%7D%7B2%7D%5D%3Dfather),发现后者值为30,可以插入,仍然满足大根堆的性质 

再尾插入60

a761c72718674ece9995f70e1cfc4af1.png

发现不满足大根堆的性质,需要一次调整

4a5e53f5f43649b1a5af1733922837dd.png

发现调整后仍然不满足大根堆的性质(56<60),需要再一次调整 

36899090ed21424586fb62e5227a50d4.png

发现调整后满足大根堆的性质(56<60<70),结束

上述的调整起名为向上调整,最多调整h(二叉树的高度)次

7.堆的实现及操作堆的函数

以大根堆为例

堆的结构体定义

可以用结构体来定义堆,由于堆的底层是用数组存储的,因此三个成员变量:数据域,大小size,容量capacity

写入头文件中

typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;

堆初始化函数HeapInit

要想使用堆必须先初始化堆(malloc,对size和capacity初始化值)

void HeapInit(HP* php)
{assert(php);php->a = (HPDataType*)malloc(sizeof(HPDataType) * 4);if (php->a == NULL){perror("malloc");return;}php->size = 0;php->capacity = 4;
}

php->capacity跟随malloc函数开辟空间的大小

堆插入元素函数HeapPush

插入前先判断空间是否充足,不够则relloc原来的2倍.之后调用向上调整函数进行插入

void HeapPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * php->capacity * 2);if (tmp == NULL){perror("realloc");return;}php->a = tmp;php->capacity *= 2;}php->a[php->size] = x;//插入至数组的最后一个元素的下一个位置(size)php->size++;//数组大小+1//调用向上调整函数AdjustUp(php->a,php->size-1);
}

注意到AdjustUp传的第二个参数是php->size-1

堆向上调整函数AdjustUp

如果a[parent] < a[child],则进行交换,之后调整parent和child的值,以便于下一次调整

写法1

void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;while (a[parent] < a[child]){Swap(&a[parent], &a[child]);//调整parent和child的值child = parent;parent = (parent - 1) / 2;}
}

写法2

void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;while (parent>=0){if (a[child] > a[parent]){Swap(&a[parent], &a[child]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}

写法3

void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;while (child>0){if (a[child] > a[parent]){Swap(&a[parent], &a[child]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}

提问

已知这几种写法都能成功运行,哪个写法存在不规范的地方?

答:从特殊情况考虑问题,写法2:

当parent==0时,进入循环,若child==1,if判断成立,交换值后,child==0,parent==-1/2==0(取商)

while(parent>=0)条件仍然成立,但不满足if (a[child] > a[parent]),因此break

不规范的地方:child==parent==0就没有必要再次进入循环,建议改成while (child>0)(写法3)

向上调整的前提

除了child位置,前面的数据结构构成堆

测试堆插入函数

main.c手动写入插入一些随机值,以下代码,下断点至return 0;

#include "Heap.h"
int main()
{HP hp;HeapInit(&hp);HeapPush(&hp, 1);HeapPush(&hp, 3);HeapPush(&hp, 0);HeapPush(&hp, 5);HeapPush(&hp, 8);HeapPush(&hp, 12);HeapPush(&hp, 2);HeapPush(&hp, 5);HeapPush(&hp, 30);HeapPush(&hp, 50);return 0;}

打开监视窗口查看

ed16365c491d4a4eb9b111b7b3f5ec30.png

画图后发现符合大根堆的性质

7ab07688e63a4274bcb0527f7b168b07.png

相关文章:

100.【C语言】数据结构之二叉树的堆实现(顺序结构) 1

目录 1.顺序结构 2.示意图 ​编辑 从物理结构还原为逻辑结构的方法 3.父子节点编号的规律 4.顺序存储的前提条件 5.堆的简介 堆的定义 堆的两个重要性质 小根堆和大根堆 6.堆的插入 7.堆的实现及操作堆的函数 堆的结构体定义 堆初始化函数HeapInit 堆插入元素函…...

大模型 VS 大语言模型

最近很多朋友搞不懂大模型和大预言模型的区别&#xff0c;总是把大模型就认为是大语言模型。 今天就用这篇帖子做一个科普。 大模型 概念&#xff1a;大模型是指拥有超大规模参数&#xff08;通常在十亿个以上&#xff09;、复杂计算结构的机器学习模型。它通常能够处理海量数…...

Linux高阶——1117—TCP客户端服务端

目录 1、sock.h socket常用函数 网络初始化函数 首次响应函数 测试IO处理函数 获取时间函数 总代码 2、sock.c SOCKET() ACCEPT()——服务端使用这个函数等待客户端连接 CONNECT()——客户端使用这个函数连接服务端 BIND()——一般只有服务端使用 LISTEN()——服务端…...

【Qt】Qt 在main.cpp中使用tr()函数报错

1. 问题 Qt 在main.cpp中使用tr()报错。 error: tr was not declared in this scope2. 解决方法 main.cpp中注意如下&#xff1a; //添加头文件 #include <QObject>//添加QObject QObject::tr("Hello")3. 参考 Qt tr()函数不起效的小问题...

面向对象高级(5)接口

面向对象高级&#xff08;5&#xff09; 接口 接口就是规范&#xff0c;定义的是一组规则&#xff0c;体现了现实世界中“如果是...则必须能...”的思想。继承是一个"是不是"的is-a关系&#xff0c;而接口实现则是 "能不能"的has-a关系。 1、接口的定义格…...

uniapp发布android上架应用商店权限

先看效果&#xff1a; 实现原理&#xff1a; 一、利用uni.addInterceptor的拦截器&#xff0c;在一些调用系统权限前拦截&#xff0c;进行弹窗展示&#xff0c;监听确定取消实现业务逻辑。 二、弹窗是原生nativeObj进行drawRect绘制的 三、权限申请调用使用的 plus.android.…...

Centos Stream 9安装Jenkins-2.485 构建自动化项目步骤

官网&#xff1a;https://www.jenkins.io/ 1 下载 环境准备&#xff1a; 版本支持查询&#xff1a;https://pkg.jenkins.io/redhat-stable/ 安装JDK17&#xff1a;https://blog.csdn.net/qq_44870331/article/details/140784297 yum -y install epel-release wget upgradew…...

电路模型和电路定理(二)

电路元件 是电路中最基本的组成单元。 电阻元件&#xff1a;表示消耗电能的元件 电感元件&#xff1a;表示产生磁场&#xff0c;储存磁场能的元件 电容元件&#xff1a;表示产生电场&#xff0c;储存电场能量的元件 电压源和电流源&#xff1a;表示将其他形式的能量转变成…...

瑞佑液晶控制芯片RA6807系列介绍 (三)软件代码详解 Part.10(让PNG图片动起来)完结篇

RA6807是RA8876M的缩小版&#xff0c;具备RA8876M的所有功能&#xff0c;只将MCU控制接口进行缩减&#xff0c;仅保留SPI-3和I2C接口&#xff0c;其它功能基本相同。 该芯片最大可控制854x600的分辨率&#xff0c;内建64Mbits显存&#xff0c;多个图层&#xff0c;使用起来相当…...

Qt常用控件 按钮

文章目录 1. QAbstractButton 简介2. QPushButton2.1 例子1&#xff0c;设置按钮的图标2.2 例子2&#xff0c;设置按钮快捷键 3. QRadioButton3.1 介绍3.2 例子1&#xff0c;选择性别3.3 例子2&#xff0c;试试其他的信号3.3 例子3&#xff0c;分组 4. QCheckBox4.1 介绍4.2 例…...

MySQL学习/复习10视图/用户/权限/语言连接数据库

一、视图 1.1创建视图 1.2视图影响基表 1.3基表影响视图 1.4删除视图 1.5视图使用规则 二、数据库的用户 2.1mysql中的user表 注意事项&#xff1a;主机/用户名/密码/权限 2.2用户的创建 注意事项&#xff1a;设置密码与登录地点需谨慎 2.3删除用户 注意事项&#xff1a;% 2.4…...

vulfocus在线靶场:tomcat-pass-getshell 弱口令 速通手册

目录 一、启动环境&#xff0c;访问页面&#xff0c;并登录&#xff0c;账号密码都是tomcat 二、哥斯拉打war包&#xff0c;图解 三、上传war包&#xff0c;图解 四、访问我们直接url/木马文件名/木马文件.jsp&#xff0c;是否存在了 五、 哥斯拉测试连接结果success&…...

c#:winform调用bartender实现打印(学习整理笔记)

效果 学习路径 C# winform调用Bartender进行自定义打印、批量打印、检索文件夹中的模板_哔哩哔哩_bilibili 一、初始环境搭建见&#xff1a; c#:winform引入bartender-CSDN博客https://blog.csdn.net/weixin_46001736/article/details/143989473?sharetypeblogdetail&s…...

牛客题库 21738 牛牛与数组

牛牛与数组题目链接 题目大意 牛牛喜欢这样的数组: 1:长度为n 2:每一个数都在1到k之间 3:对于任意连续的两个数A,B,A<=B 与(A % B != 0) 两个条件至少成立一个请问一共有多少满足条件的数组,对 1 e 9 + 7 1e^9+7 1e9+7 取模 输入格式 输入两个整数 n , k n,k n,…...

探索PDFMiner:Python中的PDF解析利器

文章目录 **探索PDFMiner&#xff1a;Python中的PDF解析利器**1. 背景介绍&#xff1a;为何选择PDFMiner&#xff1f;2. PDFMiner是什么&#xff1f;3. 如何安装PDFMiner&#xff1f;4. 简单库函数使用方法4.1 提取文本4.2 获取页面布局信息4.3 提取表格数据4.4 提取图像 5. 应…...

掌握Go语言中的异常控制:panic、recover和defer的深度解析

掌握Go语言中的异常控制:panic、recover和defer的深度解析 在Go语言的编程世界中,异常处理是一个不可忽视的话题。Go语言提供了panic、recover和defer三个关键字来处理程序中的异常情况。本文将深入探讨这三个关键字的工作原理、使用场景和最佳实践,帮助读者在实际编程中更…...

云讷科技Kerloud无人飞车专利发布

云讷科技Kerloud无人飞车获得了“一种室内外两用的四旋翼无人飞车”的实用新型专利证书&#xff0c;作为科教社区第一款四旋翼飞车&#xff0c;这项技术结合了无人机和无人车的优势&#xff0c;提供了一种能够在多种环境下使用的多功能飞行器。 这项设计的优势如下&#xff…...

企业信息化-走进身份管理之搭建篇

​一、身份管理是什么 我们先要弄懂统一身份管理到底是什么&#xff1f; 统一身份管理&#xff08;Unified Identity Manager&#xff0c;UIM&#xff09;&#xff0c;身份管理&#xff08;Identity Management&#xff0c;简称IDM&#xff09;&#xff0c;也被称为IAM&#…...

实践指南:EdgeOne与HAI的梦幻联动

在当今快速发展的数字时代&#xff0c;安全和速度已成为网络服务的基石。EdgeOne&#xff0c;作为腾讯云提供的边缘安全加速平台&#xff0c;以其全球部署的节点和强大的安全防护功能&#xff0c;为用户提供了稳定而高效的网络体验。而HAI&#xff08;HyperApplicationInventor…...

Exploring Prompt Engineering: A Systematic Review with SWOT Analysis

文章目录 题目摘要简介方法论背景相关工作评估结论 题目 探索快速工程&#xff1a;基于 SWOT 分析的系统评价 论文地址&#xff1a; https://arxiv.org/abs/2410.12843 摘要 在本文中&#xff0c;我们对大型语言模型 (LLM) 领域的提示工程技术进行了全面的 SWOT 分析。我们强…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...