数据结构——顺序二叉树——堆

1.树的相关概念

        在介绍二叉树之前,我们首先要明确树是什么。

        树用我们的通常认识来判断应该是一种植物,从根向上生长,分出许多的树枝并长出叶子。对于数据结构中的树而言,其结构也正是从树的特征中剥离出来的。树结构是一种非线性数据结构,具有一个根结点,这一个根节点连接着其他若干个结点,这些结点也同样可以连接这其他若干个结点,如此形成的数据结构我们就称为树。

        子树即树的子集,我们可以认为根节点延伸出的若干个节点实际上是若干棵子树。注意,在树形结构的定义下子树之间不允许交集的存在,即树中不允许存在环。

        一个结点或树具有一些性质,一个结点的指的是其所含有的子树的个数,而一个树的度指的是这棵树的结点中最大的度;一个结点的层次指的是其对于根节点而言所处的层数,而一个树的高度/深度指的是这棵树的结点中最大的层次。

        按照结点的度和层次特点,可以分为:根节点——第一层;叶子结点——度为0;分支结点——度不为0;根据我们生活中的伦理关系延伸,一个结点的前驱结点称为父结点,后继结点称为子节点,同一个父结点的结点称为兄弟节点

2.二叉树相关概念与存储结构

2.1 二叉树概念

        二叉树是一种特殊的树。满足度为2的树就是二叉树,所以对于任意一个二叉树的节点我们都可以将其视为是一个根节点连接着左右两个子树的结构。

        

        满二叉树是一种特殊的二叉树,其每一层结点的个数都是满的。因此对于一个n层的满二叉树,其结点个数为2^k-1个。

        完全二叉树也是一种特殊的二叉树,其与和满二叉树相似,结点按层依次排序,到所有结点连接前不允许出现空位。

         值得注意的是:二叉树的度为0的结点个数一定比度为2的结点个数多一个

2.2二叉树的存储结构

2.2.1 顺序结构

        顺序结构采取数组来存储二叉树。数组根据二叉树按层的顺序将每个结点的值存进数组的对应位置。对于一棵完全二叉树,其父子结点之间在下标上存在固定的递推关系式,对于一个根节点位于下标为0位置的树而言:左孩子下标=父结点下标*2+1右孩子下标=父结点下标*2+2父结点下标=孩子结点下标/2。根据这个规律,我们便可以在数组中存下所有的二叉树结点并可以找到结点相关联的其它结点。

        可见,顺序二叉树按位置以此存储,这就意味着如果不是完全二叉树,那么在数组中就会出现空位。因此顺序二叉树一般只会用于完全二叉树来避免空间浪费。

2.2.2 链式结构

        链式二叉树使用链表来表示,链就作为二叉树的逻辑关系指示。链式二叉树结点存储着自己的数据和两个指针,指针分别指向左孩子和右孩子,由此组成最后的完整的二叉树。链式二叉树可以存储任意形式的二叉树,我们一般采用二叉链。

2.堆

2.1 堆的概念

        对于一个集合k,将其所有元素按照顺序二叉树的方式存入一个一维数组,对任意元素k_{i},若满足k_{i}\leq k_{2*i+1}k_{i} \leq k_{2*i+2}则为小堆;若满足k_{i} \geq k_{2*i+1}k_{i} \geq k_{2*i+2}则为大堆。

        通俗解释来说:堆是一个完全二叉树,当所有的父结点都小于等于自己的子结点时,构成了小堆;当所有的父结点都大于等于自己的子结点时,构成了大堆。

 2.2 堆的工程

2.2.1 堆的定义

        因为我们已经明确了,堆是使用数组进行存储,所以堆的实现方式应该和顺序表相同。

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

 2.2.2 堆的函数接口

 2.2.2.1 堆的初始化与销毁

        堆的初始化与销毁和顺序表相同,不再过多叙述。

void HeapInit(HP* php)
{assert(php);php->data = NULL;php->capacity = php->size = 0;
}void HeapDestroy(HP* php)
{assert(php);free(php->data);php->data = NULL;php->capacity = php->size = 0;
}
2.2.2.2 堆的大小、判空、取堆顶元素

        这些都是很基础的操作,与栈和队列相似,也不再详细说道。

int HeapSize(HP* php)
{assert(php);return php->size;
}bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}HPDataType HeapTop(HP* php)
{assert(php);assert(php->size > 0);return php->data[php->size - 1];
}

2.2.3 堆的数据插入——向上调整

        对于一个堆,当我们插入一个数据的时候,这个数据会被插入到数组的尾部,也即二叉树的下一个结点处。但是我们的堆可不是那么随便的结构,小堆大堆数据之间有着自己特定的结构,这样直接在后面插入数据有可能会破坏其原有的结构,所以我们需要考虑如何再插入数据后保持其堆的特性。为此我们引入了向上调整算法

        向上调整算法目的是将新入堆的元素位置与原堆中的元素位置进行调整,使得再次构成一个堆。

        对于小堆而言,向上调整就是将子结点与其父亲相比,如果孩子小于父亲,则将二者位置调换,循环往复直到满足堆的条件为止。对于大堆而言,向上调整就是将子结点与其父亲相比,如果孩子大于父亲,则将二者位置调换,循环往复直到满足堆的条件为止。在调整过程中,每次交换后根据父子结点下标关系可以找到新的父结点与子结点。小堆和大堆的向上调整算法只在if语句中判断条件不同。

void AdjustUpMin(int* arr, int size)
{int child = size - 1;int parent = (child - 1) / 2;while (child > 0){if (arr[child] < arr[parent]){swap(&arr[child], &arr[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}
void AdjustUpMax(int* arr, int size)
{int child = size - 1;int parent = (child - 1) / 2;while (child > 0){if (arr[child] > arr[parent]){swap(&arr[child], &arr[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}

        当有了向上调整算法后,我们就可以进行数据插入了。

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

 2.2.4 堆的数据删除——向下调整

        对于堆来说,堆顶的元素是具有特殊意义的。小堆的堆顶是最小的,大队的堆顶是最大的。所以在对堆进行数据删除时,我们删除数组最后的元素意义不大,我们考虑的是取出堆顶元素后,针对元素堆顶进行删除。同理堆删除数据也会导致堆的结构被破坏,所以需要我们需要想办法恢复其堆的特性。这就需要我们设计向下调整算法

        向下调整算法的目的是将堆顶的元素与原堆中的元素交换位置,使得可以继续满足原来小堆或大堆的特征。

        对于小堆而言,向下调整是将其与子结点相比较,因为父结点需要小于子结点,所以我们需要选取左右孩子结点中较小的一个。为此我们可以假设左孩子是较小者,如果右孩子比左孩子小说明假设错误,让child+1即可。之后判断父结点与子结点的大小关系,如果满足小堆的要求就结束,否则将二者调换位置,然后找到新的父结点和子结点下标。如此循环,即可调整成为小堆。而对于大堆,和小堆同理,只是判断标准变成了父结点需要大于子节点,若父结点小于子节点则需要调整位置。

void AdjustDownMin(int* arr, int size, int parent)
{int child = parent * 2 + 1;while (child < size){if (child + 1 < size && arr[child] > arr[child + 1]){child++;}if (arr[child] < arr[parent]){swap(&arr[child], &arr[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}
void AdjustDownMax(int* arr, int size, int parent)
{int child = parent * 2 + 1;while (child < size){if (child + 1 < size && arr[child] < arr[child + 1]){child++;}if (arr[child] > arr[parent]){swap(&arr[child], &arr[parent]);parent = child;child = child * 2 + 1;}else{break;}}
}

        于是乎,我们就可以写出数据删除的函数,这里是将堆顶元素删除,然后用最后一个元素代替堆顶元素,进行向下调整。

void HeapPop(HP* php)
{assert(php);Swap(&php->data[0], &php->data[php->size - 1]);php->size--;AdjustDown(php);
}

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

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

相关文章

第二百六十六回

文章目录 1. 概念介绍2. 分析与解决2.1 分析问题2.2 解决方案 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何修改CircleAvatar的大小"相关的内容&#xff0c;本章回中将介绍如何修改StatusBar中文字的颜色.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1.…

深入理解JVM虚拟机第三十八篇:JVM中OOM的说明和举例

😉😉 欢迎加入我们的学习交流群呀! ✅✅1:这是孙哥suns给大家的福利! ✨✨2:我们免费分享Netty、Dubbo、k8s、Mybatis、Spring、Security、Docker、Grpc、消息中间件、Rpc、SpringCloud等等很多应用和源码级别高质量视频和笔记资料,你想学的我们这里都有! 🥭🥭3:…

【笔记】书生·浦语大模型实战营——第四课(XTuner 大模型单卡低成本微调实战)

【参考&#xff1a;tutorial/xtuner/README.md at main InternLM/tutorial】 【参考&#xff1a;(4)XTuner 大模型单卡低成本微调实战_哔哩哔哩_bilibili-【OpenMMLab】】 总结 学到了 linux系统中 tmux 的使用 了解了 XTuner 大模型微调框架的使用 pth格式参数转Hugging …

C++学习笔记——SLT六大组件及头文件

目录 一、C中STL&#xff08;Standard Template Library&#xff09; 二、 Gun源代码开发精神 三、 实现版本 四、GNU C库的头文件分布 bits目录 ext目录 backward目录 iostream目录 stdexcept目录 string目录 上一篇文章&#xff1a; C标准模板库&#xff08;STL&am…

原生js实现拖拽效果

<!DOCTYPE html> <html> <head> <style> #mydiv { width: 200px; height: 200px; background-color: red; position: absolute; cursor: move; } </style> | </head> <body> <div id"mydiv">拖拽我…

什么是信噪比

大家好&#xff0c;今天给大家介绍什么是信噪比&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 “信噪比”是电子技术中经常用到的一个词组&#xff0c;知道它的确切含义有一定意…

vivado18.3和modelsim关联

版本关系 首先明确Modelsim与Vivado的联合仿真需要版本号相匹配&#xff0c;Xilinx官方文档UG973中给出了所有版本的Vivado兼容Modelsim的版本情况 Vivado版本号Modelsim版本号Vivado Design Suite 2022.2Mentor Graphics ModelSim DE (2022.2)Vivado Design Suite 2022.1Men…

【前端性能优化】如何取消http请求

文章目录 需要取消http请求的3种经典场景原生XMLHttpRequest取消http请求fetch取消http请求axios取消http请求哪些情况需要取消HTTP请求取消http请求能带来哪些性能提升 需要取消http请求的3种经典场景 场景一&#xff1a;有一个实时搜索功能&#xff0c;每当用户输入内容改变的…

python爬虫小练习——爬取豆瓣电影top250

爬取豆瓣电影top250 需求分析 将爬取的数据导入到表格中&#xff0c;方便人为查看。 实现方法 三大功能 1&#xff0c;下载所有网页内容。 2&#xff0c;处理网页中的内容提取自己想要的数据 3&#xff0c;导入到表格中 分析网站结构需要提取的内容 代码 import requests…

【昕宝爸爸小模块】线程的几种状态,状态之间怎样流转

➡️博客首页 https://blog.csdn.net/Java_Yangxiaoyuan 欢迎优秀的你&#x1f44d;点赞、&#x1f5c2;️收藏、加❤️关注哦。 本文章CSDN首发&#xff0c;欢迎转载&#xff0c;要注明出处哦&#xff01; 先感谢优秀的你能认真的看完本文&…

vue中动态给不同表单赋值

这里的业务是通过关联的 id 发送不同的请求获取表单的数据&#xff0c;然后回显到页面中&#xff0c;整个的页面是由多个表单拼接起来的 点击下一步的时候&#xff0c;获取下一个表单的内容。 // 查询getForm(index) {switch (index) {case 0:this.getFromInfo("inputFor…

图鸟Vue3版本部署

无法将“pnpm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。 分析原因 这个错误信息表明在 VS Code 终端中尝试运行 pnpm install&#xff0c;但系统无法识别 pnpm 命令。这通常表示 pnpm 这个工具没有被正确安装&#xff0c;或者它的可执行文件所在的路径没有被正确…

故障诊断全家桶,看这一篇就够了,精品力荐!

本期推出故障诊断全家桶&#xff0c;包含传统的分析时频诊断方法&#xff0c;依靠数据分解方法的诊断方法&#xff0c;依靠机器学习的诊断方法。还包含了6种适应度函数随意切换的VMD优化方法&#xff0c;16种数据分解方法&#xff0c;包络谱&#xff0c;包络熵等代码。以及作者…

剪映国际版,免费无限制使用

随着抖音的爆火短视频的崛起&#xff0c;相信每一个人都感受到了短视频快节奏下的生活洪流。 现如今每个人都能成为自己生活的记录者&#xff0c;每一个人都有掌握着剪辑的基本技能。而剪映就是很多人都会使用的剪辑软件。 相对于PR、AE等剪辑软件来说&#xff0c;作为一款国…

【金猿CIO展】步长制药信息化管理与建设中心总经理束炼:IT部门既要懂技术,也要懂业务...

‍ 束炼 本文由步长制药信息化管理与建设中心总经理束炼撰写并投递参与“数据猿年度金猿策划活动——2023大数据产业年度优秀CIO榜单及奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 随着数字化转型的浪潮席卷各行各业&#xff0c;中国数字经济已进入快速发展阶…

Mybatis 常用条件语句,大于小于、if、for、模糊搜索、case when、choose

大于小于 方法1&#xff1a; > 大于 &#xff0c; < 小于 <if test"startTime ! null ">and a.create_time > #{startTime} </if> <if test"endTime ! null ">and a.create_time < #{endTime} </if> 方法2(建议写这…

PLECS如何下载第三方库并导入MOSFET 的xml文件,xml库路径添加方法及相关问题

1. 首先xml库的下载&#xff0c;PLECS提供了一个跳转的链接。 https://www.plexim.com/download/thermal_models 2. 下载一个库&#xff08;以最后一个Wolfspeed为例&#xff0c;属于CREE的SiC MOSFET&#xff09; 下载这个就行&#xff0c;都包含了。不信自己可以试试再下载…

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 例4-1 表单

代码 <!doctype html> <html> <head> <meta charset"utf-8"> <title>表单</title> </head><body> <!--<form action"URL地址" method"提交方式" name"表单名称" /*编码“多部…

【QML COOK】- 008-自定义属性

前面介绍了用C定义QML类型&#xff0c;通常在使用Qt Quick开发项目时&#xff0c;C定义后端数据类型&#xff0c;前端则完全使用QML实现。而QML类型或Qt Quick中的类型时不免需要为对象增加一些属性&#xff0c;本篇就来介绍如何自定义属性。 1. 创建项目&#xff0c;并编辑Ma…

NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver

安装显卡驱动 https://fakerth.blog.csdn.net/article/details/134659236 NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver 电脑打开分辨率直接变了&#xff0c;运行nvidia-smi报错&#xff0c;当时我就在爆发的边缘了&#xff0c;想着大好…