数据结构--二叉树和堆

目录

1.基本概念

2.树的遍历方法

3.满二叉树&&完全二叉树

4.逻辑结构&&物理结构

5.推理公式

6.二叉树应用--堆

7.简单实现堆


1.基本概念

(1)这个里面的概念还是比较多的,但是大部分我们只需要了解即可,因为这个我们在离散数学里面已经学习过一些理论知识,这个地方就不在进行这个详细的赘述了;

(2)重点就是知道这个叶子结点和终端节点,双亲节点,孩子节点,树的高度,树的高度是从1开始的,这个是和离散数学里面相互区别点一个点,重点记忆一下就行了;

(3)每一个树都是有很多的节点组成的,但是这个节点都有自己的分支,我们把一个节点的分支的个数叫做这个节点的度,其中所有节点里面的度数的最大值就是这个树的度;

2.树的遍历方法

(1)我们知道这个树肯定是有这个val表示这个节点的数值,但是这个具体要定义多少个指针,这个是不确定的,因为我们的这个树的节点的个数是不确定的;

(2)这个时候一个很厉害的定义方法就出来了,不是这个树里面的节点个数不确定吗,这个时候我们只需要定义两个节点,一个节点就是左边节点,一个节点就是右边节点;

(3)在实现这个数据结构的时候,我们只需要先定义一个指针指向这个左边的节点,让后通过一个循环,让这个节点指向他右边的兄弟节点,如果没有的话就会直接到下一个父节点,这个就可以实现这个树的遍历;

3.满二叉树&&完全二叉树

(1)满二叉树:每一个节点都有两个子节点,一个是左边的节点,一个是右边的节点;

(2)完全二叉树:上面的每一层都是满的,但是最后一层没有满,满二叉树就是特殊的完全二叉树,后面的大部分介绍对于这个满二叉树通常都是使用的完全二叉树;

4.逻辑结构&&物理结构

(1)我们之前学习这个链表就介绍过这个逻辑结构和物理结构,这个逻辑结构就是这个我们自己想的图,例如这个脸表里面不同的节点之间使用一个有方向的箭头相互连接,实际上真实存在的这个链表之间通过指针就会直接找到下一个节点了,这个箭头就是我们认为的构想出来的,实际上就是不存在的;

(2)在二叉树里面,我们的这个完全二叉树(实际上是满二叉树)也是我们认为臆想出来的,在真实存储的时候,这个是使用数组的方式进行存储的;

(3)对于一个数组的序列,我们也是可以快速地画出它的逻辑结构的,直接按照这个父子节点的顺序排列即可;

5.推理公式

(1)通过一个数组,我们可以画出对应的逻辑结构,我们接下俩就是想要得到通过这个父节点的下标,找到这个子节点的下标,通过子节点的下边,推理出来这个父节点的下标;

(2)已知这个父节点下标i,左子树就是i*2+1,右子树就是i*2+2,已知这个子树的下标j,这个时候他的父亲节点的下标就是(j-1)/2因为这个进行的除法运算,这个时候即使两个子节点对应同一个父亲节点,这个也是可以计算出来的;

(3)我们上面介绍的这个满二叉树的逻辑结构就是一个数组,但是对于一个完全二叉树(非满二叉树),如果还是使用数组进行表示,这个时候就会造成这个空间的浪费,因为这个,满二叉树和完全二叉树都是有顺序的,我们对于这个完全二叉树里面没有节点的位置,就相当于是浪费一个数组的空间,因为这个地方如果放数据,我们上面的这个父子节点下标的推理公式就不成立了;

6.二叉树应用--堆

(1)这里的堆是一种数据结构,和我们之前在C语言里面说的malloc在对堆上面开辟空间的“堆”虽然写法是一样的,但是真正的意义是不一样的,malloc是操作系统里阿米的一个区域,我们在这个区域上面开辟内存空间,和这里的数据结构对截然不同,我们在数据结构里面学习的堆是用来排序的,是一种算法;

(2)堆的分类:大堆和小堆,这个定义是根据这个子节点和父亲节点val值的大小确定的,当一个二叉树里面的任何一个父亲节点的数值都大于这个子节点的,我们就称之为一个大堆,反之就是一个小堆;

(3)通过观察我们不难发现,小堆根是最小的,大堆的根是最大的,这个就可以找到一组数据里面的极值,后续我们回去学习这个如何把一个不是堆序列的数据经过这个顺序的变换使之成为这个大堆或者小堆,或者说是这个本来开始就是一个堆序列,经过数据的添加删除之后,他依然还是一个堆序列;

(3)堆的实质就是一个完全二叉树,这个就是堆和二叉树的联系;

7.简单实现堆

(1)头文件

typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void Swap(HPDataType* p1, HPDataType* p2);
void AdjustUp(HPDataType* a, int child);
void AdjustDown(HPDataType* a, int n, int parent);void HPInit(HP* php);
void HPDestroy(HP* php);
void HPPush(HP* php, HPDataType x);

这个里面包括这个数组的初始化,销毁,数据的插入,向上调整,向下调整;

(2)对一个简单的对堆,实际上就是一个数组,只不过结构上面更加体系化,我们想要插入数据,如果这个数据插入之后,原来的小堆还是小堆,这个直接插入即可,但是如果不是,我们就需要调整,因为这个小堆的父节点的值小,说明我们这个时候插入的数据比这个父节点还小,我们就需要要向上调整,把这个插入的节点和祖先节点进行比较,直到满足这个小堆的定义才停止;

因为我们插入的数据更加小,这个函数实现的就是向上调整;

void AdjustUp(HPDataType* a, int child)
{// 初始条件// 中间过程// 结束条件int parent = (child - 1) / 2;//while (parent >= 0)while (child > 0){if (a[child] < a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}

(3)如果我们想要实现堆的删除,这个地方的删除不是删除最后一个节点,这样的话直接size--即可,完全没有其他必要了,我们要删除的是这个堆顶部元素节点;

删除的方法就是把这个堆的顶部节点和这个最后一个节点互换,我们再size--把这个节点删除,这个时候堆的顶部节点删除了,但是这个时候肯定是不满足堆的定义的,因为我们把这个堆顶元素换掉了啊,我们这个时候就需要把这个节点向下进行查找,直到符合这个堆的定义才停止;仔细观察我们会发现,这个实际上就是一个简单的排序了,但是这个还不是真正的堆排序,但是前期阶段我们可以这样进行理解;

下面是这个向下调整的实现代码:

void AdjustDown(HPDataType* a, int n, int parent)
{// 先假设左孩子小int child = parent * 2 + 1;while (child < n)  // child >= n说明孩子不存在,调整到叶子了{// 找出小的那个孩子if (child + 1 < n && a[child + 1] < a[child]){++child;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}

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

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

相关文章

Ubuntu TensorRT安装

什么是TensorRT 一般的深度学习项目&#xff0c;训练时为了加快速度&#xff0c;会使用多 GPU 分布式训练。但在部署推理时&#xff0c;为了降低成本&#xff0c;往往使用单个 GPU 机器甚至嵌入式平台&#xff08;比如 NVIDIA Jetson&#xff09;进行部署&#xff0c;部署端也…

leetcode算法题总结

leetcode算法题总结 1、面试题整理1.1 入门1.2 基础1.3 适合1-3年面试1.4 适合3年以上面试 1、面试题整理 1.1 入门 1&#xff09;两数之和&#xff08;1, easy&#xff09; 考察对map的使用&#xff0c;通过空间换时间 2&#xff09;有效的括号&#xff08;20, easy&#x…

Python的装饰器介绍

Python装饰器是一个强大的工具&#xff0c;可以增强函数或方法的功能而不改变它们的源代码。装饰器本质上是高阶函数&#xff08;即接受一个函数作为参数的函数&#xff09;&#xff0c;它允许我们在函数的入口和出口添加逻辑&#xff0c;这使得代码更简洁、更具可维护性。下面…

VSCode使用ipynb文件高效地进行功能测试

一、ipynb是什么文件 .ipynb文件是Jupyter Notebook的专用格式&#xff0c;它允许用户在一个网页应用中混合编写Markdown文本、执行代码、查看输出结果及图表。Jupyter Notebook的本质是一个Web应用程序&#xff0c;支持运行40多种编程语言&#xff0c;包括Python。它的主要用…

java反射介绍

Java反射API允许你在运行时检查和修改程序的行为。这意味着你可以动态地创建对象、查看类的字段、方法和构造函数&#xff0c;甚至调用它们。这是一个强大的特性&#xff0c;但也应该谨慎使用&#xff0c;因为它可以破坏封装性。 以下是使用Java反射的一些常见用途&#xff1a;…

403 Forbidden:深入解析 HTTP 禁止访问错误及排查方法

目录 一、理解 403 Forbidden 错误的本质 二、系统化排查 403 Forbidden 错误 三、常见的解决方法 四、错误详尽排查指南 步骤1&#xff1a;掌握基本知识 步骤2&#xff1a;确定错误范围 步骤3&#xff1a;检查显而易见的问题 步骤4&#xff1a;核对权限和访问控制 步…

【鸿蒙学习笔记】MVVM模式

官方文档&#xff1a;MVVM模式 [Q&A] 什么是MVVM ArkUI采取MVVM Model View ViewModel模式。 Model层&#xff1a;存储数据和相关逻辑的模型。View层&#xff1a;在ArkUI中通常是Component装饰组件渲染的UI。ViewModel层&#xff1a;在ArkUI中&#xff0c;ViewModel是…

[AHK V2]获取本地IP地址

问题&#xff1a;如何用AutoHotkey v2 获取本地IP地址。 解答&#xff1a;AutoHotkey v2 源代码如下 #Requires AutoHotkey v2; MsgBox GetLocalIPByAdapter(Ethernet) ; <— specify the adapter name you are interested in ; MsgBox GetLocalIPByAdapter(以太网) ; <…

《算法笔记》总结No.4——散列

散列的英文名是hash&#xff0c;即我们常说的哈希~该知识点在王道408考研的教材里面属于查找的范围。即便各位并无深入了解过&#xff0c;也听说过散列是一种更高效的查找方法。 一.引例 先来考虑如下一个假设&#xff1a;设有数组M和N分别如下&#xff1a; M[10][1,2,3,4,5,6…

ARM/Linux嵌入式面经(十三):紫光同芯嵌入式

static关键字 static关键字一文搞懂这个知识点,真的是喜欢考!!! stm32启动时如何配置栈的地址 在STM32启动时配置栈的地址是一个关键步骤,这通常是在启动文件(如startup_stm32fxxx.s,其中xxx代表具体的STM32型号)中完成的。 面试者回答: STM32启动时配置栈的地址主…

java IO流(1)

一. 文件类 java中提供了一个File类来表示一个文件或目录(文件夹),并提供了一些方法可以操作该文件 1. 文件类的常用方法 File(String pathname)构造方法,里面传一个路径名,用来表示一个文件boolean canRead()判断文件是否是可读文件boolean canWrite()判断文件是否是可写文…

早起能给我带来了什么

现在我早已养成习惯&#xff0c;每天不用闹钟也能自然醒来。有时5点起&#xff0c;有时4点半起&#xff0c;最早4点起&#xff0c;通常不晚于5点半。 相比在7点左右起床&#xff0c;我每天多出了2小时&#xff0c;按一天8小时工作时长计算&#xff0c;每年可以多出约90个工作日…

Spring懒加载Bean机制

一、概述 默认情况下Spring容器启动时就会创建被它管理的Bean&#xff0c;但是有的时候被Spring管理的Bean并不需要再容器启动的时候被创建&#xff0c;而是当对象第一次被访问的时候进行创建&#xff0c;这种场景就可以使用懒加载实现。 也就是说&#xff1a;容器启动的时候…

现场Live震撼!OmAgent框架强势开源!行业应用已全面开花

第一个提出自动驾驶并进行研发的公司是Google&#xff0c;巧的是&#xff0c;它发布的Transformer模型也为今天的大模型发展奠定了基础。 自动驾驶已经完成从概念到现实的华丽转变&#xff0c;彻底重塑了传统驾车方式&#xff0c;而大模型行业正在经历的&#xff0c;恰如自动驾…

基于S32K144驱动NSD8381

文章目录 1.前言2.芯片介绍2.1 芯片简介2.2 硬件特性2.3 软件特性 3.测试环境3.1 工具3.2 架构 4.软件驱动4.1 SPI4.2 CTRL引脚4.3 寄存器4.4 双极性步进电机驱动流程 5.测试情况6.参考资料 1.前言 最近有些做电磁阀和调光大灯的客户需要寻找国产的双极性步进电机驱动&#xf…

Android 15 应用适配默认全屏的行为变更(Android V的新特性)

简介 Android V 上默认会使用全面屏兼容方式&#xff0c;影响应用显示&#xff0c;导致应用内跟导航标题重合&#xff0c;无法点击上移的内容。 默认情况下&#xff0c;如果应用以 Android 15&#xff08;API 级别 35&#xff09;为目标平台&#xff0c;在搭载 Android 15 的设…

【SQLite3】常用API

SQLite3常用API 数据库的打开和关闭 数据库的打开&#xff08;sqlite3_open函数&#xff09; sqlite3_open() 函数用于打开一个 SQLite 数据库文件的函数&#xff0c;函数原型如下&#xff1a; int sqlite3_open(const char *filename, /* 数据库文件的文件名&#xff0c…

.net6+ 在单文件应用程序中获取程序集位置

一般来说,获取执行程序集的位置&#xff0c;您可以调用: var executableDirectory System.Reflection.Assembly.GetExecutingAssembly().Location;如果发布为单个文件, 会提示如下警告 warning IL3000: System.Reflection.Assembly.Location always returns an empty string…

解析Java中1000个常用类:EnumMap类,你学会了吗?

在线工具站 推荐一个程序员在线工具站&#xff1a;程序员常用工具&#xff08;http://cxytools.com&#xff09;&#xff0c;有时间戳、JSON格式化、文本对比、HASH生成、UUID生成等常用工具&#xff0c;效率加倍嘎嘎好用。 程序员资料站 推荐一个程序员编程资料站&#xff1a;…

python破解字母已知但大小写未知密码

python穷举已知字符串中某个或多个字符为大写的所有情况 可以使用递归函数来实现这个功能。以下是一个示例代码&#xff1a; def generate_uppercase_combinations(s, index0, current):if index len(s):print(current)returngenerate_uppercase_combinations(s, index 1, …