【二叉树】的顺序存储(堆的实现)

📙作者简介: 清水加冰,目前大二在读,正在学习C/C++、Python、操作系统、数据库等。

📘相关专栏:C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。

欢迎点赞 👍 收藏 ⭐留言 📝 如有错误还望各路大佬指正!

✨每一次努力都是一种收获,每一次坚持都是一种成长✨       

在这里插入图片描述

目录

 前言

1. 堆

  1.1 什么是堆

  1.2 堆的性质

2. 堆的实现

 2.1 堆的向下调整 

 2.2 堆的向上调整

 2.3 堆的创建

 2.3.1 定义堆

2.3.2 初始化和销毁

2.3.3 入堆

2.4 出堆

 2.5 堆顶元素、判空、堆的数据个数

总结


 前言

        我们常见的二叉树有顺序存储和链式存储,顺序存储就是使用数组来存储二叉树,除了顺序存储,堆存储也是一种常见的选择。堆存储是一种基于数组的存储方式,它使用数组来表示堆的结构。在堆存储中,我们可以使用简单的数学公式来计算节点在数组中的索引,从而实现高效的访问和操作。


1. 堆

  1.1 什么是堆

        堆是一种特殊的二叉树,使用堆存储的二叉树都是完全二叉树,堆又可分为大堆和小堆。

大堆:大堆的子节点不得大于父节点。

小堆:小堆的子节点不得小于父节点。

 可见文章:二叉树的存储结构

  1.2 堆的性质

         堆具有以下两个重要的性质:堆是一个完全二叉树,且堆中的每个节点的值都大于或等于(或小于或等于)其子节点的值,这被称为堆的堆序性质。

2. 堆的实现

 2.1 堆的向下调整 

         我们知道,堆是使用数组存储的,那任何一个数组都可以是堆吗?当然不是,对具有两个重要的性质,要想构成堆,就需要对数组的数据进行调整。调整后,逻辑上就是一颗完全二叉树。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

 如下图:

         在逻辑上是一个完全二叉树,根节点的值是30,根节点的左右子树都是小堆,为了使整颗二叉树形成堆,就需要对数据进行调整。(小堆的子节点不得小于它的父节点

 30比15大,就向下进行调整,15与30位置交换:

以此类推,进行调整:

 最终,被调整为一个小堆。(也可以调整为大堆)。

根据上述的逻辑,我们对向小调整的代码进行实现:

void HeapAdjustDown(HeapDatatype* data,int n,int parent)
{int child = parent * 2 + 1;while (child<n)			//这里不能child+1<n{if (child+1<n && data[child + 1] < data[child])//改大堆两个if的符号都要改{child++;}if(data[child]<data[parent]){swap(&data[parent], &data[child]);//后续需要多次进行调用交换函数,就封装成一个函数parent = child;child = parent * 2 + 1;}else{break;}}}

        传入一个堆、节点个数和父节点,通过父节点与孩子节点进行比较,找到较小的孩子,然后进行交换。n可以用于判断结束。注意:这里存在比较坑的点,这里我们使用了child+1,就需要判断child+1是否会越界的问题。

那为什么不在while循环处判断?

        如果在while处判断就会产生新的bug,上述的例子无法展现,我们假设上述的二叉树,需要把30调整到60的位置,那30就会先和56进行交换,然后把child赋值给parent,child=child*2+1,赋值后,child就变成60这个节点,child+1就是空,那最后一次交换就不会执行。

 2.2 堆的向上调整

         堆可以向下调整,那也可以进行向上调整,向上调整和向下调整十分的相似,也是进行比较然后交换。向上调整也更为简单一些。流程如下:

         假设传入的子节点是80,80和父节点进行比较,80大进行交换,然后再和父节点比较,80仍然较大,再进行交换,直到形成一个堆结束。(此处为大堆),向下调整我们写的是调整小堆,这里我们向上调整也调整为小堆。代码如下:

void HeapAdjustUP(HeapDatatype* data, int child) {int parent = (child - 1) / 2;while (child > 0){if (data[child] < data[parent]) //回调函数qsort的compare函数{swap(&data[child], &data[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}

        写代码时要注意:判断循环结束的条件,这里为什么不用parent>0进行判断?如果最后需要对整棵树的根节点进行交换,parent是可以等于0的,而child等于0时,即最终树的根节点交换完毕,如果再-1除2,还是0.所以拿child>0作为判断条件即可,如果没有交换到根节点,就已经构成了堆,那就break跳出循环即可。

 2.3 堆的创建

         注意上述堆的调整我们传入的参数,并不是创建的Heap(堆),而是以数组的形式传入,这样我们就可以直接调用这两个函数接口进行建堆。

for (int i = ; i < ; i++)
{AdjustUp(arr, i);
}

        只需这样就可以构建一个堆。这里我们就不进行细说,后续的堆排序会进行介绍。这里我们用老常规的方法,创建一个顺序表,然后进行建堆。

 2.3.1 定义堆

 顺序表的定义就非常常规了,和之前一样:

typedef int HeapDatatype;
typedef struct Heap {HeapDatatype* data;int size;int capacity;
}HP;

2.3.2 初始化和销毁

 初始化

void InitHeap(HP* php) {assert(php);php->data = NULL;php->size = 0;php->capacity = 0;
}

 销毁

void DestoryHeap(HP* php) {assert(php);free(php->data);php->data = NULL;php->capacity = php->size = 0;
}

 初始化和销毁都很常规,和顺序表一致。

2.3.3 入堆

         把数据入堆,先把数据入到顺序表中,然后进行调整。我们可以调用向上调整或者向下调整,只是传入的参数不同。

 代码如下:

void PushHeap(HP* php, HeapDatatype data) {assert(php);if (php->capacity == php->size){int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;HeapDatatype* tmp = (HeapDatatype*)realloc(php->data, sizeof(HeapDatatype) * newcapacity);if (tmp == NULL){perror("realloc fail");exit(-1);}php->data = tmp;php->capacity = newcapacity;}php->data[php->size++] = data;HeapAdjustUP(php->data, php->size - 1);
}

使用循环调用入堆接口,就可以完成堆的创建。

2.4 出堆

         出堆,我们可以来思考一下,出堆是单纯的将数组最后一个数据删除掉吗?当然不是,如果只是单纯的删除最后的数据,那和顺序表又有什么区别,这样做是没有意义的。

        堆在数组中的第一个元素一定是这个数组中的最值(最大或最小值),所有我们出堆,删除的是数组中的第一个元素,也就是二叉树的根。那我们要怎么去删除呢?直接删除二叉树的根?

 如下图:

         如果直接删除二叉树的根节点,剩下的部分产生的结构就会发生变化,变化后的二叉树还是堆吗?所以说直接删除的方法是不可行的。那要如何删除呢?

        我们可以这样搞:可以先把数组的第一个元素和最后一个元素进行交换,然后删除最后一个元素,最后再进行调整。这样就既可以删除根节点,而又不打乱堆的结构。

 根据这个逻辑,代码实现如下:

void PopHeap(HP* php)
{assert(php);assert(php->size > 0);swap(&php->data[0], &php->data[php->size - 1]);php->size--;									HeapAdjustDown(php->data,php->size,0);}

注意这里只能使用向下调整

 2.5 堆顶元素、判空、堆的数据个数

 剩余部分就非常简单了

//堆顶元素
HeapDatatype HeapTop(HP* php)
{assert(php);assert(php->size > 0);return php->data[0];
}
//判空
bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}
//堆的数据个数
int HeapSize(HP* php) {assert(php);return php->size;
}

最后我们可以来测试一下,我的测试代码如下:

int main()
{HP hp;int arr[6] = { 70,65,100,32,50,60 };InitHeap(&hp);for (int i = 0; i < 6; i++){PushHeap(&hp, arr[i]);}HeapPrint(&hp);printf("堆的数据个数:%d\n", HeapSize(&hp));while (!HeapEmpty(&hp)){printf("%d ", HeapTop(&hp));PopHeap(&hp);}DestoryHeap(&hp);
}

总结

        无论是学习数据结构还是应用数据结构,了解和理解堆存储都是非常有价值的。希望本篇博客能够为大家提供有价值的知识和见解,帮助大家更好地理解堆。最后,感谢阅读!

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

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

相关文章

64位Ubuntu20.04.5 LTS系统安装32位运行库

背景&#xff1a; 在ubutu&#xff08;版本为20.04.5 LTS&#xff09;中运行./arm-none-linux-gnueabi-gcc -v 后提示“no such device”。 经多方查证&#xff0c;是ubutu的版本是64位的&#xff0c;而需要运行的编译工具链是32位的&#xff0c;因此会不兼容。 解决方法就是在…

十分钟理解OSPF路由协议

十分钟理解OSPF路由协议 1.RIP的缺陷以跳数为度量值最大跳数为15更新路由表采用全更新收敛速度慢 2.RIP与OSPF比较OSPF概述运行OSPF协议之前运行OSPF协议之后 3.OSPF协议工作过程1.发现邻居2.建立邻接关系3.传递链路状态信息4.计算路由 4.OSPF分区域管理 有RIP协议&#xff0c;…

Bootstrap 框架学习笔记(基础)

来自于 Twitter&#xff0c;基于 HTML、CSS、JavaScript。 有关网站&#xff1a;Bootstrap中文网Bootstrap是Twitter推出的一个用于前端开发的开源工具包。它由Twitter的设计师Mark Otto和Jacob Thornton合作开发&#xff0c;是一个CSS/HTML框架。目前&#xff0c;Bootstrap最…

Java Semaphore使用例子和流程

目录 Semaphore例子代码和输出semaphore.acquire();semaphore.release(); Semaphore semaphore : 英[ˈseməfɔː(r)] 美[ˈseməfɔːr] n. 旗语; 信号标; v. 打旗语; (用其他类似的信号系统)发信号; [例句]Semaphore was widely used at sea, before the advent of electr…

ssh登录时间久或登陆后报错

情况1 问题描述&#xff1a; ssh登录时间很久&#xff0c;登录后出现abrt-cli status timed out 的报错 问题原因&#xff1a; .lock文件被锁导致 执行systemctl status abrtd.service可以看到被锁的.lock 处理方式&#xff1a; ps -ef | grep pid 找到被锁的进程kill掉…

图片格式大全

青春不能回头&#xff0c;青春也没有终点。 大全介绍 图片格式有多种&#xff0c;每种格式都有其独特的特性和用途。以下是一些常见的图片格式以及它们的介绍&#xff1a; JPEG&#xff08;Joint Photographic Experts Group&#xff09;&#xff1a; 文件扩展名&#xff1a;…

1786_MTALAB代码生成把通用函数生成独立文件

全部学习汇总&#xff1a; GitHub - GreyZhang/g_matlab: MATLAB once used to be my daily tool. After many years when I go back and read my old learning notes I felt maybe I still need it in the future. So, start this repo to keep some of my old learning notes…

计算机竞赛 深度学习 python opencv 火焰检测识别

文章目录 0 前言1 基于YOLO的火焰检测与识别2 课题背景3 卷积神经网络3.1 卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV54.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 数据集准备5.1 数…

QT记事本+登陆界面的简单实现

主体头文件 #ifndef JSB_H #define JSB_H#include <QMainWindow> #include <QMenuBar>//菜单栏 #include <QToolBar>//工具栏 #include <QStatusBar>//状态栏 #include <QTextEdit>//文本 #include <QLabel>//标签 #include <QDebug&g…

Android之MediaCodec::PostAndAwaitResponse消息原理(四十三)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

企业内部安全与风控管理图解

企业内部安全说外部安全&#xff0c;企业领导者都非常关注&#xff0c;由于各方面原因&#xff0c;。。。力不从心&#xff0c;妥协&#xff01; 方向&#xff1a; 1、制度 结合企业实情&#xff0c;编制企业安全管理制度 2、硬件 处理常规硬件外观&#xff0c;加壳与锁定、…

【力扣每日一题】2023.9.10 打家劫舍Ⅳ

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目翻译有些烂&#xff0c;我来二次翻译一下&#xff0c;找出数组中k个两两互不相邻的数&#xff0c;求出它们的最大值。要求最大值尽可…

Mac 错误zsh: command not found: brew解决方法

打开iterm或其他shell终端&#xff0c;执行命令&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 选择下载brew的源&#xff0c;输入1~6任意都行 根据提示输入Y及开机密码 最后执行&#xff1a;source ~/.z…

ChatGLM 大模型应用构建 Prompt 工程

文章目录 一、大模型简介1.1 大模型基础知识1.2 大模型分类 二、如何构建大模型应用2.1 To B、To C场景应用区别2.2 大模型在To B场景中的应用原则2.3 大模型应用技巧2.3.1 大模型应用技巧2.3.2 大模型的应用方法2.3.3 案例&#xff1a;车险问答系统 三、指令工程&#xff08;p…

macOS 中 Apple Distribution 与 Apple Development 证书不受信任解决方法

造成这个现象的原因是 Worldwide Developer Relations 中间关系证书缺失 我们只需要将相关证书下载并导入到「系统」级钥匙串即可 首先访问网站&#xff1a;https://www.apple.com/certificateauthority 下载右侧 Apple Intermediate Certificates 下方的如下证书 Develope…

安理【2022】

关键字&#xff1a; 出栈序列s2固定、快速排序2趟、next数组、二分查找比较次数log2n向上取整、 一、选择 二、填空 三、应用

ThreeJS-3D教学一基础场景创建

Three.js 是一个开源的 JS 3D 图形库&#xff0c;用于创建和展示高性能、交互式的 3D 图形场景。它建立在 WebGL 技术之上&#xff0c;并提供了丰富的功能和工具&#xff0c;使开发者可以轻松地构建令人惊叹的 3D 可视化效果。 Three.js 提供了一套完整的工具和 API&#xff0…

《Kubernetes部署篇:Ubuntu20.04基于外部etcd+部署kubernetes1.25.14集群(多主多从)》

一、部署架构图 1、架构图如下所示: 2、部署流程图如下所示: 二、环境信息 1、资源下载基于外部etcd+部署容器版kubernetes1.25.14集群资源合集 2、部署规划主机名K8S版本系统版本内核版本IP地址备注k8s-master-121.25.14Ubuntu 20.04.5 LTS5.15.0-69-generic192.168.1.12ma…

乐鑫科技全球首批支持蓝牙 Mesh Protocol 1.1 协议

乐鑫科技 (688018.SH) 非常高兴地宣布&#xff0c;其自研的蓝牙 Mesh 协议栈 ESP-BLE-MESH 现已支持最新蓝牙 Mesh Protocol 1.1 协议的全部功能&#xff0c;成为全球首批在蓝牙技术联盟 (Bluetooth SIG) 正式发布该协议之前支持该更新的公司之一。这意味着乐鑫在低功耗蓝牙无线…

CHATGPT中国免费网页版有哪些-CHATGPT中文版网页

CHATGPT中国免费网页版&#xff0c;一个强大的人工智能聊天机器人。如果你曾经感到困惑、寻求答案&#xff0c;或者需要一些灵感&#xff0c;那么CHATGPT国内网页版可能会成为你的好朋友。 CHATGPT国内免费网页版&#xff1a;你的多面“好朋友” 随着人工智能技术的不断发展&a…