二叉树--堆(上卷)

二叉树–堆(上卷)

树的概念与结构

树是⼀种⾮线性的数据结构,它是由 n(n>=0) 个有限结点组成⼀个具有层次关系的集合。把它叫做 树是因为它看起来像⼀棵倒挂的树,也就是说它是根朝上,⽽叶朝下的。

• 有⼀个特殊的结点,称为根结点,根结点没有前驱结点。

• 除根结点外,其余结点被分成 M(M>0) 个互不相交的集合 T1、T2、……、Tm ,其中每⼀个集合 Ti(1 <= i <= m) ⼜是⼀棵结构与树类似的⼦树。每棵⼦树的根结点有且只有⼀个前驱,可以 有 0 个或多个后继。因此,树是递归定义的。

在这里插入图片描述

树形结构中,⼦树之间不能有交集,否则就不是树形结构

⾮树形结构:

在这里插入图片描述

  • ⼦树是不相交的(如果存在相交就是图了)
  • 除了根结点外,每个结点有且仅有⼀个⽗结点
  • ⼀棵N个结点的树有N-1条边

树相关术语

在这里插入图片描述

⽗结点/双亲结点: 若⼀个结点含有⼦结点,则这个结点称为其⼦结点的⽗结点; 如上图:A是B的⽗ 结点

⼦结点/孩⼦结点: ⼀个结点含有的⼦树的根结点称为该结点的⼦结点; 如上图:B是A的孩⼦结点

结点的度: ⼀个结点有⼏个孩⼦,他的度就是多少;⽐如A的度为6,F的度为2,K的度为0

树的度: ⼀棵树中,最⼤的结点的度称为树的度; 如上图:树的度为 6

**叶⼦结点/终端结点:**度为 0 的结点称为叶结点; 如上图: B、C、H、I… 等结点为叶结点

分⽀结点/⾮终端结点: 度不为 0 的结点; 如上图: D、E、F、G… 等结点为分⽀结点

兄弟结点: 具有相同⽗结点的结点互称为兄弟结点(亲兄弟); 如上图: B、C 是兄弟结点

**结点的层次:**从根开始定义起,根为第 1 层,根的⼦结点为第 2 层,以此类推;

**树的⾼度或深度:**树中结点的最⼤层次; 如上图:树的⾼度为 4

**结点的祖先:**从根到该结点所经分⽀上的所有结点;如上图: A 是所有结点的祖先

**路径:**⼀条从树中任意节点出发,沿⽗节点-⼦节点连接,达到任意节点的序列;⽐如A到Q的路径为: A-E-J-Q;H到Q的路径H-D-A-E-J-Q

⼦孙: 以某结点为根的⼦树中任⼀结点都称为该结点的⼦孙。如上图:所有结点都是A的⼦孙

森林: 由 m(m>0) 棵互不相交的树的集合称为森林;

==注意点:==上面这些概念特别需要关注的是深度的概念要好好理解,其他和人类社会的关系差不多

树的表示

孩⼦兄弟表⽰法:

树结构相对线性表就⽐较复杂了,要存储表⽰起来就⽐较⿇烦了,既然保存值域,也要保存结点和结 点之间的关系,实际中树有很多种表⽰⽅式如:双亲表⽰法,孩⼦表⽰法、孩⼦双亲表⽰法以及孩⼦ 兄弟表⽰法等。我们这⾥就简单的了解其中最常⽤的孩⼦兄弟表⽰法

struct TreeNode
{
struct Node* child; // 左边开始的第⼀个孩⼦结点
struct Node* brother; // 指向其右边的下⼀个兄弟结点
int data; // 结点中的数据域
};

在这里插入图片描述

树形结构实际运⽤场景

⽂件系统是计算机存储和管理⽂件的⼀种⽅式,它利⽤树形结构来组织和管理⽂件和⽂件夹。在⽂件 系统中,树结构被⼴泛应⽤,它通过⽗结点和⼦结点之间的关系来表⽰不同层级的⽂件和⽂件夹之间 的关联。

在这里插入图片描述

接下来,我们要引入一个非常重要且应用非常广泛的概念叫做二叉树

二叉树是树形结构的一种

二叉树

概念与结构

在树形结构中,我们最常⽤的就是⼆叉树,⼀棵⼆叉树是结点的⼀个有限集合,该集合由⼀个根结点 加上两棵别称为左⼦树和右⼦树的⼆叉树组成或者为空。

在这里插入图片描述

从上图可以看出⼆叉树具备以下特点:

  1. ⼆叉树不存在度⼤于 2 的结点 (也就是说度只有0,1,2,三种情况)

  2. ⼆叉树的⼦树有左右之分,次序不能颠倒,因此⼆叉树是有序树

    注意:对于任意的⼆叉树都是由以下⼏种情况复合⽽成的
    在这里插入图片描述

现实中的⼆叉树

在这里插入图片描述

特殊的⼆叉树

满⼆叉树

⼀个⼆叉树,如果每⼀个层的结点数都达到最⼤值,则这个⼆叉树就是满⼆叉树。也就是说,如果⼀ 个⼆叉树的层数为 K ,且结点总数是 2k − 1 ,则它就是满⼆叉树。

在这里插入图片描述

完全二叉树

完全⼆叉树是效率很⾼的数据结构,完全⼆叉树是由满⼆叉树⽽引出来的。对于深度为 K 的,有 n 个 结点的⼆叉树,当且仅当其每⼀个结点都与深度为K的满⼆叉树中编号从 1 ⾄ n 的结点⼀⼀对应时称 之为完全⼆叉树。要注意的是满⼆叉树是⼀种特殊的完全⼆叉树。

(也就是说满二叉树是完全二叉树,但是完全二叉树不是满二叉树)
在这里插入图片描述

注意点:
在这里插入图片描述

💡 ⼆叉树性质

根据满⼆叉树的特点可知:

1)若规定根结点的层数为 1 ,则⼀棵⾮空⼆叉树的第i层上最多有 2i−1 个结点

2)若规定根结点的层数为 1 ,则深度为 h 的⼆叉树的最⼤结点数是 2h-1

3)若规定根结点的层数为 1 ,具有 n 个结点的满⼆叉树的深度 h=log2(n+1)( log 以2为底, n+1 为对数)

注意点:2)和上面提到的k就相当于换了个字母,3)2h-1=n去进行计算

⼆叉树存储结构

⼆叉树⼀般可以使⽤两种结构存储,⼀种顺序结构,⼀种链式结构。

顺序结构

顺序结构存储就是使⽤数组来存储,⼀般使⽤数组只适合表⽰完全⼆叉树,因为不是完全⼆叉树会有 空间的浪费,完全⼆叉树更适合使⽤顺序结构存储。
在这里插入图片描述

现实中我们通常把堆(⼀种⼆叉树)使⽤顺序结构的数组来存储,需要注意的是这⾥的堆和操作系统 虚拟进程地址空间中的堆是两回事,⼀个是数据结构,⼀个是操作系统中管理内存的⼀块区域分段。

链式结构

⼆叉树的链式存储结构是指,⽤链表来表⽰⼀棵⼆叉树,即⽤链来指⽰元素的逻辑关系。 通常的⽅法 是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别⽤来给出该结点左孩⼦和右孩 ⼦所在的链结点的存储地址 。

链式结构⼜分为⼆叉链和三叉链,这里是初阶数据结构,我们重点讨论二叉链。
在这里插入图片描述

实现顺序结构二叉树

⼀般堆使⽤顺序结构的数组来存储数据,堆是⼀种特殊的⼆叉树,具有⼆叉树的特性的同时,还具备 其他的特性。

堆的概念与结构

如果有⼀个关键码的集合 ,把它的所有元素按完全⼆叉树的顺序存储⽅ 式存储,在⼀个⼀维数组中,并满⾜: ( 且 ), i = 0、1、2… ,则称为⼩堆(或⼤堆)。将根结点最⼤的堆叫做最⼤堆或⼤根堆,根结点最⼩的堆 叫做最⼩堆或⼩根堆。
在这里插入图片描述

堆具有以下性质

• 堆中某个结点的值总是不⼤于或不⼩于其⽗结点的值;

• 堆总是⼀棵完全⼆叉树。

注意点: 小堆堆顶是堆最小值;

​ 大堆堆顶是堆最大值。

​ 数组不一定是有序的

💡 ⼆叉树性质

• 对于具有 n 个结点的完全⼆叉树,如果按照从上⾄下从左⾄右的数组顺序对所有结点从 0 开始编号,则对于序号为 i 的结点有:

  1. 若 i>0 , i 位置结点的双亲序号: (i-1)/2 ; i=0 , i 为根结点编号,⽆双亲结点
  2. 若 2i+1<n,左孩⼦序号: 2i+1 >=n,否则⽆左孩⼦
  3. 若 2i+2<n ,右孩⼦序号:2i+2>=n,否则无右孩子

注意点:

性质1是子节点去推父节点;性质2和3是父节点去计算子节点,父节点–>左孩子:2i+1;右孩子:2i+2

堆的实现

因为堆的底层结构是数组,所以和前面实现顺序表的内容差不多,这里也就不作过多的赘述,可以看我前面写的有关顺序表的博客

链接如下:http://t.csdnimg.cn/ixSyC

但是堆的向上调整算法和堆的向下调整算法是不一样的,也非常的重要

堆的向上调整算法

在这里插入图片描述

代码如下:

//交换两个元素
void Swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}
//堆的向上调整算法
void AdjustUp(HPDataType* arr, int child)
{int parent = (child - 1) / 2;while (child > 0)//此时已经在头结点的位置,不是在根节点,不用等于0{if (arr[child] < arr[parent]){Swap( &arr[parent],&arr[child]);child = parent;parent = (child - 1) / 2;}else{break;}}
}

堆的向上调整算法是应用于插入数据的

堆的向下调整算法

在这里插入图片描述

我们的宗旨是不影响堆这个结构

//堆的向下调整
void AdjustDown(HPDataType* arr, int parent, int n)
{int child = 2 * parent + 1;//左孩子while (child<n){if (child + 1 && arr[child] > arr[child + 1]){child++;//比较孩子大小}if (arr[parent] > arr[child]){Swap( &arr[child],&arr[parent]);}else{break;}}
}

代码如下:

Heap.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>//定义堆的结构--数组
typedef int HPDataType;
typedef struct Heap
{HPDataType* arr;int size;//有效的数据个数int capacity;//空间大小
}HP;
void HPInit(HP* php);//初始化
void HPDestory(HP* php);//销毁
void HPPush(HP* php, HPDataType x);//插入数据
void HPPop(HP* php);//删除数据
HPDataType HPTop(HP* php);//取堆顶元素
bool HPEmpty(HP* php);//判空

Heap.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Heap.h"
//初始化
void HPInit(HP* php)
{assert(php);php->arr = NULL;//首先数组先置空php->size =php->capacity = 0;
}
//销毁
void HPDestory(HP* php)
{assert(php);if (php->arr)//和顺序表的销毁类似,要去判断数组是否存在free(php->arr);php->arr = NULL;php->size = php->capacity = 0;
}
//交换两个元素
void Swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}
//堆的向上调整算法
void AdjustUp(HPDataType* arr, int child)
{int parent = (child - 1) / 2;while (child > 0)//此时已经在头结点的位置,不是在根节点,不用等于0{if (arr[child] < arr[parent]){Swap( &arr[parent],&arr[child]);child = parent;parent = (child - 1) / 2;}else{break;}}
}
//插入数据
void HPPush(HP* php, HPDataType x)
{//空间不够if (php->size == php->capacity){//扩容int newCapacity=php->capacity == 0?4 : 2 * php->capacity;HPDataType* tmp = (HPDataType*)realloc(php->arr,newCapacity*sizeof(HPDataType));if (tmp == NULL){perror("realloc fail!");exit(1);}php->arr = tmp;php->capacity = newCapacity;}//空间足够php->arr[php->size]=x;AdjustUp(php->arr, php->size);++php->size;
}
//堆的向下调整
void AdjustDown(HPDataType* arr, int parent, int n)
{int child = 2 * parent + 1;//左孩子while (child<n){if (child + 1 && arr[child] > arr[child + 1]){child++;//比较孩子大小}if (arr[parent] > arr[child]){Swap( &arr[child],&arr[parent]);}else{break;}}
}
//出堆:出的是堆顶的数据
void HPPop(HP* php)
{assert(php && php->size);//arr[0] arr[size-1]Swap(&php->arr[0], &php->arr[php->size - 1]);//为了不影响总体二叉树的结构--php->size;AdjustDown(php->arr, 0, php->size);//0是堆顶位置对应的下标
}
//判空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}
//取堆顶元素
HPDataType HPTop(HP* php)
{assert(php && php->size);return php->arr[0];
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Heap.h"
void HPTest01()
{HP hp;HPInit(&hp);int arr[] = { 17,20,10,13,19,15 };for (int i = 0; i < 6; i++){HPPush(&hp, arr[i]);}//打印while (!HPEmpty(&hp)){printf("%d ", HPTop(&hp));HPPop(&hp);}HPDestory(&hp);
}
int main()
{HPTest01();return 0;
}

最终的结果如下:

ert(php && php->size);
return php->arr[0];
}


test.c```C
#define _CRT_SECURE_NO_WARNINGS 1
#include "Heap.h"
void HPTest01()
{HP hp;HPInit(&hp);int arr[] = { 17,20,10,13,19,15 };for (int i = 0; i < 6; i++){HPPush(&hp, arr[i]);}//打印while (!HPEmpty(&hp)){printf("%d ", HPTop(&hp));HPPop(&hp);}HPDestory(&hp);
}
int main()
{HPTest01();return 0;
}

最终的结果如下:

在这里插入图片描述

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

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

相关文章

智慧医院信息系统思维导图

智慧医院信息系统 "思维导图智慧医院信息系统, 用一张图解析智慧医疗信息系统 本文转载&#xff1a;有了这个智慧医院信息系统思维导图&#xff0c;没人不明医疗信息化

是时候学习Grid布局了

一、序言 先说什么&#xff1f;当然先说大家最关心的兼容性了 CanIUse 嗯&#xff0c;对于非要兼容IE的开发者&#xff0c;我建议&#xff0c;量力而行&#xff01;兼容性还是不如Flex 当然&#xff0c;如果你flex够熟悉了&#xff0c;但却被一些布局有时候难倒&#xff0c;我…

学习react-登录状态验证

1.创建三个页面LoginPage, HomePage,NotFoundPage用于Router 创建LoginPage.tsx用于做登录页面 // LoginPage.tsx const LoginPage (props:LoginProp) > {const navigate useNavigate();return( <h1 onClick{ ()>{navigate("/");}}>Hello Login, {pr…

昇思25天学习打卡营第1天 | 快速入门教程

昇思大模型平台&#xff0c;就像是AI学习者和开发者的超级基地&#xff0c;这里不仅提供丰富的项目、模型和大模型体验&#xff0c;还有一大堆经典数据集任你挑。 AI学习有时候就像找不到高质量数据集的捉迷藏游戏&#xff0c;而且本地跑大数据集训练模型简直是个折磨&#xf…

JQuery简单实现ul li点击菜单项被选中的菜单项保持高亮状态(导航ul li点击切换样式)

效果&#xff1a; JS&#xff1a; $(function () {//遍历list&#xff08;一般为ul li&#xff09;$("#menu a").each(function () {//给当前项添加点击事件&#xff08;点击后切换样式&#xff09;$(this).bind(click,function () {// 移除其他所有项的active类$(&…

挑战房市预测领头羊:KNN vs. 决策树 vs. 线性回归

挑战房市预测领头羊&#xff08;KNN&#xff0c;决策树&#xff0c;线性回归&#xff09; 1. 介绍1.1 K最近邻&#xff08;KNN&#xff09;&#xff1a;与邻居的友谊1.1.1 KNN的基础1.1.2 KNN的运作机制1.1.3 KNN的优缺点 1.2 决策树&#xff1a;解码房价的逻辑树1.2.1 决策树的…

【日常设计案例分享】通道对账

今天跟同事们讨论一个通道对账需求的技术设计。鉴于公司业务线有好几个&#xff0c;为避免不久的将来各业务线都重复竖烟囱&#xff0c;因此&#xff0c;我们打算将通道对账做成系统通用服务&#xff0c;以降低各业务线的开发成本。 以下文稿&#xff08;草图&#xff09;&…

局部变量,在使用时再定义

关于局部变量&#xff0c;适时定义局部变量&#xff0c;可提高代码清晰度和可读性&#xff0c;并能规避不必要的代码bug 局部变量&#xff0c;在使用时再定义&#xff0c;提高代码可读性 下面代码中的2个方法&#xff0c;第1个 verifyTaskApply 调用第2个 existAppliedTask 。…

20240730 每日AI必读资讯

&#x1f3ac;燃爆&#xff01;奥运8分钟AI影片火了&#xff0c;巴赫主席&#xff1a;感谢中国黑科技 - 短片名为《永不失色的她》&#xff08;To the Greatness of HER&#xff09;&#xff0c;由阿里巴巴和国际奥委会联合推出。 - 百年奥运史上伟大女性的影响故事在此被浓缩…

Rust语言入门第七篇-控制流

文章目录 Rust语言入门第七篇-控制流If 表达式基本结构特点和规则示例 let 语句中使用 ifloop 循环基本结构特点示例综合示例 while 循环基本结构特点示例综合示例 与 loop 循环的区别 for 循环基本结构详细说明特点示例综合示例 Rust语言入门第七篇-控制流 Rust 的控制流是指…

Oracle Database 23.5 - for Engineered Systems版本发布

要尝鲜的可以在https://edelivery.oracle.com/下载。对于x86的本地版本再等等吧。 安装可参考飞总的&#xff1a;oracle 23ai&#xff08;23.5.0.24.07&#xff09;完整功能版安装体验 – 提供7*24专业数据库(Oracle,SQL Server,MySQL,PostgreSQL等)恢复和技术支持Tel:1781323…

Python数值计算(12)

本篇说说Neville方法。Neville方法的基础是&#xff0c;插值多项式可以递归的生成&#xff0c;有时进行插值的目的是为了计算某个点的值&#xff0c;这个时候并不需要将拟合曲线完全求出&#xff0c;而是可以通过递归的方式进行计算&#xff0c;具体操作如下&#xff1a; 例如…

OpenGL学习 1

一些唠叨&#xff1a; 很多时候&#xff0c;都被Live2d吸引&#xff0c;去年想给网页加个live2d看板娘&#xff0c;结果看不懂live2d官方给的SDK&#xff0c;放弃了。今天又想弄个live2d桌宠&#xff0c;都已经在网上找到Python 的 Live2D 拓展库了&#xff0c;并提供了用QT实现…

昇思25天学习打卡营第19天|ResNet50 图像分类案例:数据集、训练与预测可视化

目录 环境配置 数据集加载 数据集可视化 Building Block Bottleneck 构建ResNet50网络 模型训练与评估 可视化模型预测 环境配置 首先指出实验环境预装的 mindspore 版本以及更换版本的方法。然后&#xff0c;它卸载了已安装的 mindspore 并重新安装指定的 2.3.0rc1 版本…

值得买科技与MiniMax达成官方合作伙伴关系,共建融合生态

7月29日&#xff0c;值得买科技与大模型公司MiniMax宣布达成官方合作伙伴关系。 MiniMax旗下大模型产品海螺AI现已接入值得买“消费大模型增强工具集”&#xff0c;基于海螺AI比价策略&#xff0c;用户可通过海螺AI“悬浮球”功能实现快速比价及跳转购买。 此次合作也标志着值…

操作系统重点总结

文章目录 1. 操作系统重点总结1.1 操作系统简介1.1.1 操作系统的概念和功能1.1.2 操作系统的特征1.1.2.1 并发1.1.2.2 共享1.1.2.3 虚拟1.1.2.4 异步 1.1.3 操作系统的发展与分类1.1.4 中断和异常1.1.5 系统调用1.1.6 操作系统的体系结构1.1.7 操作系统简介总结 1.2 进程1.2.1 …

使用YApi平台来管理接口

快速上手 进入YApi官网&#xff0c;进行注册登录https://yapi.pro/添加项目 3. 添加分类 4. 添加接口 5. 添加参数 添加返回数据 可以添加期望 验证 YAPI&#xff08;Yet Another Practice Interface&#xff09;是一个现代化的接口管理平台&#xff0c;由淘宝团队…

企业邮箱如何进行邮件监控

企业邮箱监控保障资产安全、合规性&#xff0c;防范网络攻击&#xff0c;提升员工行为。核心要素包括内容扫描、行为分析、合规性检查等。实施策略涉及技术选择、政策制定、员工培训。企业邮箱如何进行邮件监控呢&#xff1f;Zoho邮箱的eDiscovery功能可实现长期邮件保存和监控…

基于百度paddle检索系统的召回

所谓召回&#xff0c;无非就是用一段不规则文本模拟用户query查询&#xff0c;而要召回的是标准的titlekey,这些是要构建索引库的&#xff0c;所有相似文本对的第二个文本必须要在索引库里存在&#xff0c;不然就没法评估,因为标记都是0,还有召回1&#xff0c;召回5等,并不是什…

在Ubuntu 22 VPS服务器上更改phpMyadmin端口的方法

更改 Ubuntu 22 VPS服务器上的 phpMyAdmin 端口可以增强安全性和可管理性。但是具体应该怎么操作呢&#xff1f;接下来将带您了解在Ubuntu 22 VPS 服务器上更改phpMyadmin的端口全过程&#xff0c;一起来看看吧。 准备你的环境 在开始之前&#xff0c;让我们先确保你已做好一…