二叉树-堆的详解

一,树的概念

1,树的概念

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。

把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

有一个特殊的结点,称为根结点,根结点没有前驱结点

除根结点外,其余结点被分成M(M>0)个互不相交的集合

T1、T2、……、Tm,其中每一个集合Ti(1<= i <= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继

因此,树是递归定义的

注意:树形结构中,子树之间不能有交集,否则就不是树形结构

2,树的相关概念

3,二叉树的概念

一棵二叉树是结点的一个有限集合,该集合:

1. 或者为空

2. 由一个根结点加上两棵别称为左子树和右子树的二叉树组成

1. 二叉树不存在度大于2的结点

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

注意:对于任意的二叉树都是由以下几种情况复合而成的: 

特殊的二叉树:

1. 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是 说,如果一个二叉树的层数为K,且结点总数是 ,则它就是满二叉树。

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

 

 节点与高度关系

设高度为h,节点个数为N  

 

4,堆的概念

如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足: = 且 >= ) i = 0,1, 2…,则称为小堆(或大堆)。将根结点最大的堆叫做最大堆或大根堆,根结点最小的堆叫做最小堆或小根堆。  

物理:数组

逻辑:完全二叉树

堆的性质

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

堆总是一棵完全二叉树。

二,堆的实现

老规矩建立三个文件 Heap.c Heap.h Test.c

 1,堆的结构

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

2,堆的初始化

void HPInit(HP* php);

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

3,堆的销毁

void HPDestroy(HP* php);

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

4,数据的交换

 void Swap(HPDataType* p1, HPDataType* p2);

void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}

5,向上调整(小堆为例)

void AdjustUp(HPDataType* a, int child);

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;}}
}

条件while (parent >= 0) 不准确,由于child==0时,parent = (child - 1) / 2;是整型还是为0,故可以实现 

6,堆的插入

void HPPush(HP* php, HPDataType x);

判断空间是否足够

if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, newcapacity * sizeof(HPDataType));if (tmp == NULL){perror("realloc fail");return;}

插入数据

php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;

调整数据

AdjustUp(php->a, php->size - 1);

总代码

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

 

 

 

  

7,堆的删除(删除堆顶)

挪动覆盖删除堆顶数据,会导致堆的关系错误

可以将堆顶数据和堆尾数据互换,这样其两个左右子树还是小堆,然后使用向下调节算法 

 

void HPPop(HP* php);

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

8,向下调整(小堆为例) 

 void AdjustDown(HPDataType* a, int n, int parent);

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;}}
}

 9,取堆顶数据

HPDataType HPTop(HP* php);

HPDataType HPTop(HP* php)
{assert(php);assert(php->size > 0);return php->a[0];
}

10,判断堆是否为空

bool HPEmpty(HP* php);

bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}

 三,堆的应用

利用堆排序

向上调整建堆

for (int i = 1; i < n; i++){AdjustUp(a, i);}

 向下调整建堆

for (int i = (n-1-1)/2; i >= 0; i--){AdjustDown(a, n, i);}

完整代码

void HeapSort(int* a, int n)
{// 降序,建小堆// 升序,建大堆/*for (int i = 1; i < n; i++){AdjustUp(a, i);}*/for (int i = (n-1-1)/2; i >= 0; i--){AdjustDown(a, n, i);}int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}
}

 

不可以用大堆进行降序,因为首先第一个定死了,后面接着用大堆会使关系错乱

建堆时间复杂度 

向下调整

因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的 就是近似值,多几个结点不影响最终结果):

 

向下调整建堆 O(N) 

向上调整

 

向上调整建堆O(N*logN)

n个数找最大的前K个

方法一

建一个N个数的大堆  O(N)

pop k次 O(K*logN)

方法二

用前k个数 建一个小堆 O(K)

剩下的数跟堆顶数据比较,如果比堆顶数据大,就替代堆顶数据进堆(覆盖跟位置然后向下调整)

O(log K*(N-K))

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

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

相关文章

vue3 + echarts 二次开发百分比饼图

效果图&#xff1a; 安装 pnpm i echarts 公共模块组件 <divclass"pie"ref"percent"style"width: 100%; height: calc(100% - 48px)"></div> import { ref, onMounted } from vue import * as echarts from echarts const prop…

【乐吾乐3D可视化组态编辑器】状态告警示例

状态告警的设置方法为两种&#xff1a; 1.通过数据点号设置&#xff08;推荐&#xff09;&#xff1a; 适用于绑定单一数据点号&#xff0c;设置逻辑简洁&#xff0c;实现简单逻辑交互 2.通过交互事件监听数据点号设置&#xff1a; 适用于绑定多个数据点号&#xff0c;实现复…

LLM大模型AI应用的三阶技术

第一阶 指令工程&#xff08;Prompt Enginner&#xff09; 设计提示&#xff08;Prompt Design&#xff09; 结果优化&#xff08;Response Optimization&#xff09; 交互设计&#xff08;Interaction Design&#xff09; 模型理解&#xff08;Model Understanding&#…

哈希经典题目(C++)

文章目录 前言一、两数之和1.题目解析2.算法原理3.代码编写 二、判定是否互为字符重排1.题目解析2.算法原理3.代码编写 三、 字⺟异位词分组1.题目解析2.算法原理3.代码编写 总结 前言 哈希表是一个存储数据的容器&#xff0c;我们如果想要快速查找某个元素&#xff0c;就可以…

MMUNet:形态学特征增强网络在结肠癌病理图像分割中的应用

MMUNet: Morphological feature enhancement network for colon cancer segmentation in pathological images. 发表在&#xff1a;Biomedical Signal Processing and Control2024--影响因子&#xff1a;3.137 南华大学的论文 论文地址&#xff1a;main.pdf (sciencedirecta…

Wakeup Source框架设计与实现

Wakeup Source 为系统组件提供了投票机制&#xff0c;以便低功耗子系统判断当前是否可以进入休眠。 Wakeup Source(后简称&#xff1a;WS) 模块可与内核中的其他模块或者上层服务交互&#xff0c;并最终体现在对睡眠锁的控制上。 1. 模块功能说明 WS的处理逻辑基本上是围绕 com…

后端进阶-分库分表

文章目录 为什么需要分库为什么需要分表 什么时候需要分库分表只需要分库只需要分表 分库分表解决方案垂直分库水平分库垂直分表水平分表 分库分表常用算法范围算法hash分片查表分片 分库分表模式客户端模式代理模式 今天跟着训练营学习了分库分表&#xff0c;整理了学习笔记。…

echarts的使用

一 echarts的使用 引入 echarts.js 文件 <script src"https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script> 准备一个呈现图表的盒子 <div class"container"><div class"t_header"><span>端午…

智能视频监控平台LntonCVS视频融合共享平台保障露营安全解决方案

在当今社会&#xff0c;都市生活的快节奏和压力使得越来越多的人渴望逃离城市的喧嚣&#xff0c;寻求一种短暂的慢生活体验。他们向往在壮丽的山河之间或宁静的乡村中露营&#xff0c;享受大自然的宁静与美好。随着露营活动的普及&#xff0c;露营地的场景也变得更加丰富多样&a…

使用python绘制核密度估计图

使用python绘制核密度估计图 核密度估计图介绍效果代码 核密度估计图介绍 核密度估计&#xff08;Kernel Density Estimation&#xff0c;KDE&#xff09;是一种用于估计数据概率密度函数的非参数方法。与直方图不同&#xff0c;KDE 可以生成平滑的密度曲线&#xff0c;更好地…

LeetCode62不同路径

题目描述 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。问总共有多少条不同的路径&#xff1f; …

网络基础_02

1.ARP协议 地址解析协议&#xff08;Address Resolution Protocol&#xff09; 已知对方的三层ip地址&#xff0c;需要二层mac地址 当一台设备&#xff08;请求方&#xff09;需要知道某个 IP 地址对应的 MAC 地址时&#xff0c;会使用 ARP封装一个数据帧。这台设备的网络层以…

华为RH2288H V3服务器iBMC的SSL证书续期

本文对华为RH2288H V3服务器iBMC的SSL证书续期&#xff0c;以避名登录告警提示及主机状态异常。 一、检查现网服务器iBMC的SSL证书到期时间 登录iBMC&#xff0c;点击配置--SSL证书&#xff0c;如下&#xff1a; 可以看到本服务器SSL证书将于今年7月22日到期。 二、联系厂家…

【第四节】C/C++数据结构之树与二叉树

目录 一、基本概念与术语 二、树的ADT 三、二叉树的定义和术语 四、平衡二叉树 4.1 解释 4.2 相关经典操作 4.3 代码展示 一、基本概念与术语 树(Tree)是由一个或多个结点组成的有限集合T。其中: 1 有一个特定的结点&#xff0c;称为该树的根(root)结点&#xff1b; 2 …

【Linux】进程2——管理概念,进程概念

1.什么是管理&#xff1f; 那在还没有学习进程之前&#xff0c;就问大家&#xff0c;操作系统是怎么管理进行进程管理的呢&#xff1f; 很简单&#xff0c;先把进程描述起来&#xff0c;再把进程组织起来&#xff01; 我们拿大学为例子 最典型的管理者——校长最典型的被管理…

来自工业界的知识库 RAG 服务(三),FinGLM 竞赛获奖项目详解

背景介绍 前面介绍过工业界的 RAG 服务 QAnything 和 RagFlow 的详细设计&#xff0c;也介绍过来自学术界的 一些优化手段。 前一阵子刚好看到智谱组织的一个金融大模型比赛 FinGLM&#xff0c;主要做就是 RAG 服务的竞赛&#xff0c;深入研究了其中的几个获奖作品&#xff…

Pyramid Vision Transformer, PVT(ICCV 2021)原理与代码解读

paper&#xff1a;Pyramid Vision Transformer: A Versatile Backbone for Dense Prediction without Convolutions official implementation&#xff1a;GitHub - whai362/PVT: Official implementation of PVT series 存在的问题 现有的 Vision Transformer (ViT) 主要设计…

C++结合ffmpeg获取声音的分贝值

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、分贝是什么&#xff1f;1.功率量2.场量 二、实际操作1.分析wav文件2.读取麦克风 总结 前言 最近面对一个需求&#xff0c;就是需要传递声音文件到模型里推…

链表的回文结构OJ

链表的回文结构_牛客题霸_牛客网对于一个链表&#xff0c;请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法&#xff0c;判断其是否为。题目来自【牛客题霸】https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId49&&tqId29370&rp1&a…

CodeMeter助力Hilscher,推动实现全球智能制造连接解决方案

Hilscher的旗舰店为开放工业4.0联盟&#xff08;OI4&#xff09;社区提供了应用商店的便捷和开放性&#xff0c;将这一概念引入工业领域。该商店依托CodeMeter的许可证管理和加密保护&#xff0c;为工业用户提供了丰富的应用和解决方案库&#xff0c;满足他们在车间自动化和连接…