数据结构之顺序结构二叉树(超详解)


文章目录
- 1 树
- 1.1 树的概念与结构
- 1.2 相关术语
- 1.3 树的表示与运用场景
- 1.3.1 运用场景
- 2. 二叉树
- 2.1 概念与结构
- 2.1.1 满二叉树
- 2.1.2 完全二叉树
- 3. 顺序结构二叉树
- 3.1 堆的引入
- 3.1.1 概念与结构
- 3.2 功能实现
- 3.2.1 堆的结构
- 3.2.2 初始化、销毁
- 3.3 堆的插入数据
- 3.3.1 向上调整算法
- 3.4 堆是否为空
- 3.5 删除堆顶数据
- 3.5.1 向下调整算法
- 3.5.2 获取堆顶数据
- 3.5.2.1 求有效数据个数
- 3.6 向上(下)调整算法的复杂度比较
- 3.6.1 向上调整算法时间复杂度
- 3.6.2 向下调整算法时间复杂度
- 4. 代码实现
1 树
1.1 树的概念与结构
树是⼀种非线性的数据结构,它是由 n(n>=0) 个有限结点组成⼀个具有层次关系的集合。
具有以下特点:
- 具有根节点,且根节点无前驱结点。
- 除根结点外,其余结点被分成 M(M>0) 个互不相交的集合,每⼀个集合又是⼀棵结构与树类似的子树。每棵子树的根结点仅有一个前驱结点,但可以有多个互不相交的后驱结点。(若存在相交就是图了)

1.2 相关术语
- 子结点/孩子结点:⼀个结点的子树的根结点称子结点; 如上图:B是A的子结点。
- 父结点/双亲结点:含有子结点的结点称为其子结点的父结点; 如上图:A是B的父结点。
- 结点的度:⼀个结点有几个子结点,度就是多少;如A的度为3,F的度为0。
- 树的度:⼀棵树中,最大的结点的度称为树的度; 如上图:树的度为3。
- 叶子结点/终端结点:度为 0 的结点称为叶结点; 如上图: J、K、L… 等结点为叶结点。
- 分支结点/非终端结点:度不为 0 的结点; 如上图: A、B、C、D… 等结点为分支结点。
- 兄弟结点:具有相同父结点的结点互称为兄弟结点(亲兄弟); 如上图: E、F 是兄弟结点。
- 结点的层次:从根开始定义起,根为第 1 层,根的⼦结点为第 2 层,以此类推。
- 树的高度或深度:树中结点的最大层次; 如上图:树的高度为 4。
- 结点的祖先:从根到该结点所经分支上的所有结点;如上图: A 是所有结点的祖先。
- 子孙:以某结点为根的子树中任⼀结点都称为该结点的子孙。如上图:所有结点都是A的子孙
- 路径:⼀条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列;如A到J的路径为:A-B-E-J。
- 森林:由 m(m>0) 棵互不相交的树的集合称为森林。
1.3 树的表示与运用场景
树的表示有很多种,最常用的便是孩子兄弟表示法,其很好地解决了结点和结点之间的关系。
struct TreeNode
{struct Node* child; // 左边开始的第⼀个孩⼦结点struct Node* brother; // 指向其右边的下⼀个兄弟结点int data; // 结点中的数据域
};

1.3.1 运用场景
文件系统是计算机存储和管理文件的⼀种方式,它利用树形结构来组织和管理文件和文件夹。在文件系统中,树结构被广泛应用,它通过父结点和⼦结点之间的关系来表示不同层级的文件和文件夹之间的关联。

2. 二叉树
2.1 概念与结构
⼀棵二叉树是结点的⼀个有限集合,该集合由⼀个根结点加上两棵别称为左子树和右子树的二叉树组成或者为空。

特点:
- 不存在大于度大于2的结点;
- 二叉树有左右之分,次序不能颠倒。
2.1.1 满二叉树
如果每⼀个层的结点数都达到最大值或满足结点总数是2k-1则这个二叉树就是满二叉树。
2k-1的公式推导:

总的结点数:20 + 21 + 22+……+2k-1 = 1 * (1 - 2k) / 1 - 2 = 2k-1
2.1.2 完全二叉树
规定根结点的层数为 1:
- ⼀棵非空二叉树的第i层上最多有 2i−1 个结点
- 深度为 h 的二叉树的最大结点数是 2h − 1
- 具有 n 个结点的满二叉树的深度 h = log2 (n + 1) ( log以2为底, n+1 为对数) -->满二叉树是特殊的完全二叉树。
3. 顺序结构二叉树
顺序结构存储是使用数组来存储,在实现完全二叉树能减少空间浪费。

3.1 堆的引入
3.1.1 概念与结构


- 对于序号i对应的结点,若i>0,则(i-1)/2为父结点;若i=0,则无父结点;
- 若2*i+1<n,则对应其左孩子;
- 若2*i+2<n,则对应其右孩子。
3.2 功能实现
3.2.1 堆的结构
由于堆底层是用数组实现的,因此相似于顺序表,其结构定义如下:
typedef int HPDataType;
//定义堆的结构
typedef struct HeapNode
{HPDataType* arr;int size;//有效数据个数int capacity;//容量
}HP;
3.2.2 初始化、销毁
这些代码实现已经在顺序表中介绍到。
//堆的初始化
void HPInit(HP* php)
{assert(php);php->arr = NULL;php->size = php->capacity = 0;
}
//堆的销毁
void HPDesTroy(HP* php)
{assert(php);if (php->arr)free(php->arr);php->arr = NULL;php->capacity = php->size = 0;
}
3.3 堆的插入数据
熟悉了堆的概念与结构后,我们清楚堆要不就是大根堆,要不就是小根堆。问题在于插入数据后,我们如何通过代码实现化成大根堆或者小根堆的形式?由此我们提出了向上(下)调整算法,也会带大家分析这两种算法哪种更好。

3.3.1 向上调整算法


3.4 堆是否为空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}
3.5 删除堆顶数据
- 在删除堆顶数据时,先要判断堆是否为空,因此采用assert。
- 删除堆顶数据后,如何让其再次成为大(小)根堆。

由此我们引入了向下调整算法。
3.5.1 向下调整算法
前提:左右⼦树必须是⼀个堆,才能调整。

3.5.2 获取堆顶数据
HPDataType HPTop(HP* php)
{assert(!HPEmpty(php));return php->arr[0];
}
3.5.2.1 求有效数据个数
int HPSize(HP* php)
{assert(php);return php->size;
}
3.6 向上(下)调整算法的复杂度比较
3.6.1 向上调整算法时间复杂度

根据大O表示法,则O(n*log2n) --> 详见算法复杂度篇章
3.6.2 向下调整算法时间复杂度

根据大O表示法可见时间复杂度为O(n)
因此==向下调整算法的时间复杂度更优==。
4. 代码实现
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<time.h>typedef int HPDataType;
//定义堆的结构
typedef struct HeapNode
{HPDataType* arr;int size;//有效数据个数int capacity;//容量
}HP;//堆的初始化
void HPInit(HP* php);
//堆的销毁
void HPDesTroy(HP* php);
//堆的插入数据
void HPPush(HP* php, HPDataType x);
//删除堆顶数据
void HPPop(HP* php);
//获取堆顶数据
HPDataType HPTop(HP* php);
//判空
bool HPEmpty(HP* php);
//求size
int HPSize(HP* php);//向上调整
void AdjustUp(HPDataType* arr, int child);
//向下调整
void AdjustDown(HPDataType* arr, int parent, int n);
//交换
void Swap(int* x, int* y);
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"//堆的初始化
void HPInit(HP* php)
{assert(php);php->arr = NULL;php->size = php->capacity = 0;
}
//堆的销毁
void HPDesTroy(HP* php)
{assert(php);if (php->arr)free(php->arr);php->arr = NULL;php->capacity = php->size = 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){//>:大堆//<:小堆if (arr[child] > arr[parent]){//交换Swap(&arr[child], &arr[parent]);child = parent;parent = (child - 1) / 2;}else {break;}}
}
//堆的插入数据
void HPPush(HP* php, HPDataType x)
{assert(php);//判断空间是否不足if (php->size == php->capacity){int newCapacity = php->capacity == 0 ? 4 : 2 * php->capacity;//空间不足需要增容HPDataType* tmp = (HPDataType*)realloc(php->arr, sizeof(HPDataType) * newCapacity);if (tmp == NULL){perror("realloc fail!");exit(1);}//realloc成功php->arr = tmp;php->capacity = newCapacity;}php->arr[php->size] = x;//向上调整AdjustUp(php->arr, php->size - 1);php->size++;
}//向下调整
void AdjustDown(HPDataType* arr, int parent, int n)
{int child = parent * 2 + 1;while (child < n){if (child + 1 < n && arr[child] < arr[child + 1]){child++;}//>建小堆//<建大堆if (arr[parent] < arr[child]){Swap(&arr[parent], &arr[child]);parent = child;child = parent * 2 + 1;}else {break;}}
}
//删除堆顶数据
void HPPop(HP* php)
{assert(!HPEmpty(php));Swap(&php->arr[0], &php->arr[php->size - 1]);php->size--;//向下调整AdjustDown(php->arr, 0, php->size);
}
//获取堆顶数据
HPDataType HPTop(HP* php)
{assert(!HPEmpty(php));return php->arr[0];
}
//判空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}
//求size
int HPSize(HP* php)
{assert(php);return php->size;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"void test()
{HP hp;HPInit(&hp);HPPush(&hp, 1);HPPush(&hp, 3);HPPush(&hp, 2);HPPush(&hp, 4);/*HPPop(&hp);HPPop(&hp);HPPop(&hp);HPPop(&hp);*/while (!HPEmpty(&hp)){printf("%d ", HPTop(&hp));HPPop(&hp);}HPDesTroy(&hp);
}void test01()
{int arr[] = { 14,51,31,21,23,32 };int n = sizeof(arr) / sizeof(arr[0]);HP hp;HPInit(&hp);//调用push将数组中的数据建堆for (int i = 0;i < n;i++){HPPush(&hp, arr[i]);}int i = 0;while (!HPEmpty(&hp)){arr[i++] = HPTop(&hp);HPPop(&hp);}for (int i = 0;i < n;i++){printf("%d ", arr[i]);}HPDesTroy(&hp);
}int main()
{test();test01();//int arr[] = { 14,51,31,21,23,32 };//int n = sizeof(arr) / sizeof(arr[0]);Bubblesort(arr,n);//HeapSort(arr,n);//for (int i = 0;i < n;i++)//{// printf("%d ", arr[i]);//}//CreateDate();TopK();return 0;
}


相关文章:
数据结构之顺序结构二叉树(超详解)
文章目录 1 树1.1 树的概念与结构1.2 相关术语1.3 树的表示与运用场景1.3.1 运用场景 2. 二叉树2.1 概念与结构2.1.1 满二叉树2.1.2 完全二叉树 3. 顺序结构二叉树3.1 堆的引入3.1.1 概念与结构 3.2 功能实现3.2.1 堆的结构3.2.2 初始化、销毁 3.3 堆的插入数据3.3.1 向上调整算…...
acwing_5722_十滴水
acwing_5722_十滴水 下面这篇大佬的题解属实是把指针用明白了,可以好好理解一下: 原题解连接:AcWing 5722. 一个简单模拟实现 - AcWing map/unordered_map的用法:见收藏夹 #include<iostream> #include<unordered_map> #incl…...
acwing-3194 最大的矩形
acwing-3194 最大的矩形 这个题程序设计课上有讲过, 平民算法,时间复杂度在 O ( n 2 ) O(n^2) O(n2) // // Created by HUAWEI on 2024/10/28. // #include<iostream>using namespace std;const int Max_size 1e4 20;int N; int h[Max_size];…...
UnityDemo-TheBrave-制作笔记
这是我跟着b站up主MStudio的视频学习制作的,大体上没有去做一些更新的东西,这里只是一个总的总结。在文章的最后,我会放上可以游玩该游戏的链接和exe可执行文件,不过没有对游戏内容进行什么加工,只有基本的功能实现罢了…...
玩转 JMeter:Random Order Controller让测试“乱”出花样
嘿,各位性能测试的小伙伴们!今天咱要来唠唠 JMeter 里超级有趣又超实用的 Random Order Controller(随机顺序控制器),它就像是性能测试这场大戏里的“魔术棒”,轻轻一挥,就能让测试场景变得千变…...
VTK知识学习(33)-交互问题2
1、前言 主要是针对前面有过实现不了交互的情况进行说明,经过一些尝试和分析调用API,总算实现RenderWindowControl函数回调正常串接,当然这个移动处理事件的效果目前也没有确认。 2、使用 vtkImageReslice reslice vtkImageReslice.New();p…...
Centos9-SSH免密登录配置-修改22端口-关闭密码登录-提高安全性
Centos9-SSH免密登录配置-修改22端口-关闭密码登录 生成秘钥对将公钥信息存进authorized_keys测试登录查询访问记录、比对指纹更换22访问端口关闭账号密码登录生成秘钥对 生成密钥对,指定 备注 和 文件目录命令执行后,默认两次回车,不设置秘钥使用密码ssh-keygen -t rsa -b …...
SqlServer: An expression services limit has been reached异常处理
在工作中遇到一个问题,因为项目很老,代码很不规范,出现一种场景: 查询所有客户(5w条以上),然后根据客户Id,再去其他表查询,代码中是直接将customerId拼接到sql中去查询,形成的sql如…...
CentOS下安装Docker
Docker 必须要在Linux环境下才能运行,windows下运行也是安装虚拟机后才能下载安装运行,菜鸟教程 下载安装 linux 依次执行下边步骤 更新 yum yum update 卸载旧的Docker yum remove docker docker-client docker-client-latest docker-common doc…...
WPF控件Grid的布局和C1FlexGrid的多选应用
使用 Grid.Column和Grid.Row布局,将多个C1FlexGrid布局其中,使用各种事件来达到所需效果,点击复选框可以加载数据到列表,移除列表的数据,自动取消复选框等 移除复选框的要注意!!!&am…...
Jenkins-持续集成、交付、构建、部署、测试
Jenkins-持续集成、交付、构建、部署、测试 一: Jenkins 介绍1> Jenkins 概念2> Jenkins 目的3> Jenkins 特性4> Jenkins 作用 二:Jenkins 版本三:DevOps流程简述1> 持续集成(Continuous Integration,CI࿰…...
高级第一次作业
1、shell 脚本写出检测 /tmp/size.log 文件如果存在显示它的内容,不存在则创建一个文件将创建时间写入。 2、写一个 shel1 脚本,实现批量添加 20个用户,用户名为user01-20,密码为user 后面跟5个随机字符。 3、编写个shel 脚本将/usr/local 日录下大于10M的文件转移到…...
Copula算法原理和R语言股市收益率相依性可视化分析
阅读全文:http://tecdat.cn/?p6193 copula是将多变量分布函数与其边缘分布函数耦合的函数,通常称为边缘。在本视频中,我们通过可视化的方式直观地介绍了Copula函数,并通过R软件应用于金融时间序列数据来理解它(点击文…...
反弹SHELL不回显带外正反向连接防火墙出入站文件下载
什么是反弹shell 正向连接正向连接(Forward Connection):正向连接是一种常见的网络通信模式,其中客户端主动发起连接到服务器或目标系统。正向连接通常用于客户端-服务器通信,客户端主动请求服务或资源,例如…...
后盾人JS--JS值类型使用
章节介绍与类型判断 看看构造函数 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</t…...
1月11日
[WUSTCTF2020]CV Maker 可以看到有个注册页面,尝试注册一个用户登进去看看 进来后第一眼就看到文件上传,尝试上传,上传php后返回了 文件上传后端检测exif_imagetype()函数 他提示不是image,也就是需要我们构造一个文件头为图像类…...
【深度学习】Pytorch:加载自定义数据集
本教程将使用 flower_photos 数据集演示如何在 PyTorch 中加载和导入自定义数据集。该数据集包含不同花种的图像,每种花的图像存储在以花名命名的子文件夹中。我们将深入讲解每个函数和对象的使用方法,使读者能够推广应用到其他数据集任务中。 flower_ph…...
最近在盘gitlab.0.先review了一下docker
# 正文 本猿所在产品的代码是保存到了一个本地gitlab实例上,实例是别的同事搭建的。最近又又又想了解一下,而且已经盘了一些了,所以写写记录一下。因为这个事儿没太多的进度压力,索性写到哪儿算哪儿,只要是新了解到的…...
OA项目登录
导入依赖,下面的依赖是在这次OA登录中用到的 <!--web依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.sprin…...
verilogHDL仿真详解
前言 Verilog HDL中提供了丰富的系统任务和系统函数,用于对仿真环境、文件操作、时间控制等进行操作。(后续会进行补充) 正文 一、verilogHDL仿真详解 timescale 1ns/1ps //时间单位为1ns,精度为1ps, //编译…...
AI智能体架构设计:从成本黑洞到价值引擎的解耦之道
1. 从成本黑洞到价值引擎:为什么你的AI智能体架构正在吞噬预算又到了季度技术复盘会,财务那边递过来的云账单和工程人力成本,是不是又让你倒吸一口凉气?你看着报表上那个名为“AI智能体平台”的项目,它的资源消耗曲线几…...
用Python+OpenCV手把手实现Prewitt边缘检测(附完整代码与效果对比图)
用PythonOpenCV手把手实现Prewitt边缘检测(附完整代码与效果对比图) 边缘检测是计算机视觉中最基础也最关键的预处理步骤之一。想象一下,当你需要让计算机"看清"一张照片中的物体轮廓时,边缘检测算法就是它的"视觉…...
本地柴油发电机组排行2023年最新榜单
柴油发电机是通过燃烧柴油驱动发动机,进而发电的设备,广泛应用于电力中断或无电网地区。1. 柴油发电机的核心工作原理是什么?柴油发电机是一种将化学能转化为电能的设备,其核心是柴油发动机与交流发电机的组合。当柴油在发动机内燃…...
古戏台构件声学特性的时域有限差分方法【附模型】
✨ 长期致力于时域有限差分法、窑洞、戏台、八字墙、共形技术研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,点击《获取方式》 (1)曲面共形网格快速生成算法: …...
百考通智能任务书:贴合你的选题,拒绝空话假大空
毕业设计任务书是高校教学管理中的关键环节,它不仅标志着研究工作的正式启动,更是后续开题、实施、论文撰写和答辩全过程的行动依据。然而,许多学生在撰写时常常因不熟悉本专业写作规范、技术表达能力有限,或缺乏权威模板参考而陷…...
2026年HR招聘偏好白皮书:这5项附加技能出现频率暴涨
2026 年的招聘市场,正在从“看你会什么岗位技能”,转向“看你能不能把岗位做得更智能”。HR筛简历时,越来越关注候选人的AI应用能力、数据化思维和业务落地能力。人社部近年发布的新职业中,已经出现生成式人工智能系统应用员、人工…...
Blender渲染通道完全指南:如何像电影后期一样,分离出深度、阴影与反射图
Blender渲染通道完全指南:影视级后期制作的深度解析在数字内容创作领域,Blender已经从一个简单的3D建模工具成长为能够处理复杂视觉特效的全流程解决方案。对于追求影视级质量的中高级用户而言,掌握渲染通道技术是提升作品专业度的关键一步。…...
ARM PMU外部接口与性能监控寄存器详解
1. ARM性能监控寄存器外部接口深度解析性能监控单元(PMU)是现代处理器架构中用于硬件性能分析的核心模块,它通过一组可编程计数器实时捕获处理器微架构层面的各类事件。在ARMv8/v9架构中,PMU不仅可以通过系统寄存器访问,还提供了标准化的外部…...
App Inventor蓝牙调试避坑指南:从连接失败到数据乱码,一次讲清所有常见问题
App Inventor蓝牙调试避坑指南:从连接失败到数据乱码的实战解决方案在移动应用开发领域,蓝牙通信一直是实现设备间短距离数据交换的核心技术之一。对于使用App Inventor的开发者而言,蓝牙模块提供了无需复杂编码即可实现无线通信的便捷途径。…...
钱钟书《围城》第1-5章阅读笔记:一场关于人生困境的提前预演
前言 钱钟书先生的《围城》被誉为"新儒林外史",是中国现代文学史上风格独特的讽刺经典。这部创作于20世纪40年代的长篇小说,以抗战初期为背景,通过主人公方鸿渐的人生轨迹,深刻揭示了知识分子群体的精神困境与人性弱点。…...
