数据结构(7)—— 二叉树(1)
目录
前言
一、 树概念及结构
1.1树的概念
1.2树的相关概念
1.3数的表示
1.二叉树表示
2.孩子兄弟表示法
3.动态数组存储
1.4树的实际应用
二、二叉树概念及结构
2.1概念
2.2特殊的二叉树
1.满二叉树
2. 完全二叉树
2.3二叉树的性质
2.4二叉树的存储结构
1.顺序存储
2.链式存储
三、二叉树的顺序结构实现
3.1二叉树的顺序结构
3.2堆的概念及其结构
3.3堆的实现
3.3.1结构体定义
3.3.2初始化
3.3.3向上调整(大堆)
3.3.4向下调整(大堆)
3.3.5插入
3.3.6删除头
3.3.7获取堆顶元素
3.3.8检查空
3.3.9获取个数
测试
总结
前言
本文介绍二叉树以及堆的认识,以及对于堆的介绍和代码编写。
一、 树概念及结构
1.1树的概念
树是一种非线性的数据结构,由节点(Node)和边(Edge)组成,是由n(n>=0)个有限结点组成一个具有层次关系的集合。树结构具有层次性,通常用于表示具有父子关系的数据。
有一个特殊的结点,称为根结点,根节点没有前驱结点。
除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<= i <= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继因此,因此树是递归定义的。
要注意:
树中子树不能相交,就如之前说的子树的根节点有且只有一个前驱一样,除了根节点以外,每一个子节点有且只有一个根结点,子树不能有交集,否则就不是树形结构,一棵树N个节点那么它有N-1条边。
1.2树的相关概念
一颗树中每一个部分都有自己的名字,针对上面的一个数对树的相关概念进行解释:
节点的度:一个节点包含所有子树的个数成为这个节点的度;例如上面的A节点的度就是6。
叶节点或终端节点:度为0的节点;例如上面的LMJK就是叶节点。
双亲节点或父节点:若一个节点含有子节点,那么这个节点就是其子节点的父节点;例如A就是B的父节点。
孩子节点或父节点:一个节点含有的子树的根节点称为该节点的子节点;上面B就是A的孩子节点。
兄弟节点:具有相同父节点的节点称为兄弟节点;B、C就是兄弟节点,它们的共同父节点就是A。
树的度:一棵树中,最大的节点的度称为数的度;上面就是6。
节点的吃层次:从跟开始定义,跟为第1层,跟的子节点为第2层,以此类推;
树的高度或深度:树中节点的最大层次;上面就是4层。
堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上面的E和F就是互为堂兄弟。
节点的祖先:从跟到该节点所经分支上的所有节点;A就是所有节点的祖先。
子孙:以某节点为跟的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙。
森林:由m(m>0)棵互不相交的数的集合称为森林。
1.3数的表示
树的表示有很多种,这里介绍几种树的表示方法:
1.二叉树表示
二叉树是最基础的树的结构,每一个节点有两个子节点(左子树和右子树),当然还包括一个data用来存储数据。
// 定义二叉树节点结构
struct TreeNode {int data;struct TreeNode* left;struct TreeNode* right;
};
2.孩子兄弟表示法
孩子兄弟表示法是构建普通数的常用方式。
// 多叉树节点结构(孩子兄弟表示法)
struct TreeNode {int data;struct TreeNode* firstChild; // 第一个孩子节点struct TreeNode* nextSibling; // 兄弟节点
};
3.动态数组存储
当然,使用动态数组也可以实现多叉树节点的结构:
// 多叉树节点结构(动态数组)
struct TreeNode {int data;int childCount;struct TreeNode* children[MAX_CHILDREN];
};
1.4树的实际应用
文件系统管理
文件系统的目录结构通常采用树形组织,根目录为顶层节点,子目录和文件作为子节点。这种结构便于用户导航和管理文件。
数据库索引
B树和B+树是数据库索引的核心数据结构,能够高效支持数据的插入、删除和查询操作,保持对数级的时间复杂度。
网络路由
路由器使用前缀树(Trie)存储IP路由表,快速匹配最长前缀路由规则,优化数据包转发效率。
人工智能决策
决策树通过树形分支模拟人类决策过程,每个节点代表一个判断条件,广泛应用于分类和回归任务。
组织结构管理
企业组织架构常表现为树形,CEO为根节点,各部门经理为子节点,清晰反映汇报关系和职责划分。
XML/HTML解析
DOM树将文档表示为节点树,每个标签作为节点,父子关系反映标签嵌套层级,便于程序分析和操作。
游戏开发
场景图使用树结构管理游戏对象,父子节点关系实现坐标系的层级变换,优化渲染效率。
编译器设计
抽象语法树(AST)表示源代码的语法结构,每个节点对应语言构造,支撑语义分析和代码生成。
二、二叉树概念及结构
2.1概念
一颗二叉树,顾名思义,只能有两个度,所以二叉树是一个有限集合,该集合要么为空,要么每一个根节点加上左右子树组成,同时二叉树有左右之分,次序不能颠倒,因此二叉树是有序树。
2.2特殊的二叉树
1.满二叉树
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是 ,则它就是满二叉树。

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

2.3二叉树的性质
1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有
2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是个结点.
.
3. 对任何一棵二叉树, 如果度为0其叶结点个数为 , 度为2的分支结点个数为 ,则有 n0= n2+1
4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=. (ps: 是log以2为底,n+1为对数)。
5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:1. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
2. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
3. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子
2.4二叉树的存储结构
二叉树一般有两种存储结构,一种是顺序结构,一种是链式结构。
1.顺序存储
数序存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树的话,中间有空挡,本身数组就是一段连续的存储地址,那么就会有浪费的空间,而现实中只有堆才会使用数组来存储,二叉树顺序存储本身就是物理上的一个数组,在逻辑上就是一颗二叉树。
2.链式存储
用链表来表示一颗二叉树,用链来指示元素的逻辑关系,通常的方法就是链表中每个节点由三个域组成,数据域和左右指针域,左右指针分别用来给出该节点左孩子和右孩子所在的链节点的存储地址,一般都是二叉链,其中红黑树是用到的三叉链。
三、二叉树的顺序结构实现
3.1二叉树的顺序结构
普通的二叉树是不适合使用数组来进行存储的,因为可能会出现大量的空间浪费,只有完全二叉树才更适合顺序结构存储,现实中我们把堆用顺序结构来存储。
3.2堆的概念及其结构
堆是一种特殊的完全二叉树,分为最大堆和最小堆。最大堆中每个节点的值都大于或等于其子节点的值,最小堆中每个节点的值都小于或等于其子节点的值。堆常用于实现优先队列和堆排序算法,将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。


堆的性质:
1.堆中某个节点的值总是不大于或不小于其父节点的值;
2.堆总是一颗完全二叉树;
3.3堆的实现
我们通过实现这些:
void HeapInit(HP* php);//初始化
void HeapPush(HP* php, HPDataType x);//尾插
void HeapPop(HP* php);//删除头
void AdjustDown(HPDataType* a, int n, int parent);//向下调整
void AdjustUp(HPDataType* a, int child);//向上调整
HPDataType HeapTop(HP* php);//堆顶元素
bool HeapEmpty(HP* php);//检查空
int HeapSize(HP* php);//堆数据的个数
3.3.1结构体定义
typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;
3.3.2初始化
void HeapInit(HP* php)
{assert(php);php->a = (HPDataType*)malloc(sizeof(HPDataType)*4);//分配4空间if (php->a == NULL){perror("malloc fail");return;}php->size = 0;//当前数据个数php->capacity = 4;//空间大小
}
3.3.3向上调整(大堆)
//前提是除了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;}}
}
函数通过计算父节点索引 parent = (child - 1) / 2
定位当前节点的父节点。循环条件 child > 0
确保不会越界,避免了使用 parent >= 0
可能导致的潜在问题。当子节点值大于父节点值时,调用 Swap
交换两者位置,并更新子节点和父节点的索引。如果子节点值不大于父节点值,循环终止,堆性质已满足。
3.3.4向下调整(大堆)
//前提左右子树都是大堆或者小堆
//向下调整,取大换小
void AdjustDown(HPDataType* a, int n, int parent)
{int child = parent * 2 + 1;while (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;}elsebreak;}
}
函数接收三个参数:堆数组a
、堆的大小n
、需要调整的父节点索引parent
。初始化时计算左孩子索引:child = parent * 2 + 1
。循环条件为当前孩子节点在堆范围内(child < n
)。在循环体内,先比较左右孩子节点的大小(确保右孩子存在的情况下),选择较大的孩子节点。如果较大的孩子节点大于父节点,则交换两者位置,并继续向下调整。如果父节点已经大于或等于两个孩子节点,则调整完成,退出循环。
3.3.5插入
void HeapPush(HP* php,HPDataType x)
{assert(php);if (php->size == php->capacity){HPDataType* tmp = (HPDataType*)realloc(php->a,sizeof(HPDataType) * php->capacity*2);if (tmp == NULL){perror("realloc fail");return;}php->a = tmp;php->capacity *= 2;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}
3.3.6删除头
//删除堆顶才有意义,也就是删除根,不断的筛选大根堆小跟堆的根节点,从而实现排序,挑出最大最小的
void HeapPop(HP* php)
{assert(php);assert(!HeapEmpty(php));//删除数据Swap(&php->a[0], &php->a[php->size - 1]);php->size--;AdjustDown(php->a,php->size,0);
}
3.3.7获取堆顶元素
HPDataType HeapTop(HP* php)
{assert(php);return php->a[0];
}
3.3.8检查空
bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}
3.3.9获取个数
int HeapSize(HP* php)
{assert(php);return php->size;
}
测试
void HeapSort(int* a, int n)
{//建堆//1.向上调整建堆for (int i = 1; i < n; ++i){AdjustUp(a, i);//模拟插入建堆,降序}
}
//排升序不能建小堆,得建大堆
// 排降序应该建小堆
//排升序第一个数排好了,但是剩下的数关系全乱了int main()
{int a[10] = { 2,1,5,7,6,8,0,9,4,3 };//对数组排序HeapSort(a, 10);return 0;
}
总结
本文介绍了大小堆的创建以及对于一组数据通过大小堆来实现最后的升序和降序排序。
相关文章:

数据结构(7)—— 二叉树(1)
目录 前言 一、 树概念及结构 1.1树的概念 1.2树的相关概念 1.3数的表示 1.二叉树表示 2.孩子兄弟表示法 3.动态数组存储 1.4树的实际应用 二、二叉树概念及结构 2.1概念 2.2特殊的二叉树 1.满二叉树 2. 完全二叉树 2.3二叉树的性质 2.4二叉树的存储结构 1.顺序存储 2.链式存储…...
ROS1和ROS2的区别autoware.ai和autoware.universe的区别
文章目录 前言一、ROS1和ROS2的区别一、ROS2通讯实时性比ROS1强二、ROS1官方不再维护了三、ROS2的可靠性比ros1强四、ROS2的安全性比ros1强五、ROS2资源占用低六、等等等等 二、autoware.ai和autoware.universe的区别一、autoware.ai不维护了二、autoware.universe功能多&#…...

如何使用 Docker 部署grafana和loki收集vllm日志?
环境: Ubuntu20.04 grafana loki 3.4.1 问题描述: 如何使用 Docker 部署grafana和loki收集vllm日志? 解决方案: 1.创建一个名为 loki 的目录。将 loki 设为当前工作目录: mkdir loki cd loki2.将以下命令复制并粘贴到您的命令行中,以将 loki-local-config.yaml …...

Kafka入门- 基础命令操作指南
基础命令 主题 参数含义–bootstrap-server连接的Broker主机名称以及端口号–topic操作的topic–create创建主题–delete删除主题–alter修改主题–list查看所有主题–describe查看主题的详细描述–partitions设置分区数–replication-factor设置分区副本–config更新系统默认…...

目标检测我来惹1 R-CNN
目标检测算法: 识别图像中有哪些物体和位置 目标检测算法原理: 记住算法的识别流程、解决问题用到的关键技术 目标检测算法分类: 两阶段:先区域推荐ROI,再目标分类 region proposalCNN提取分类的目标检测框架 RC…...

lua的笔记记录
类似python的eval和exec 可以伪装成其他格式的文件,比如.dll 希望在异常发生时,能够让其沉默,即异常捕获。而在 Lua 中实现异常捕获的话,需要使用函数 pcall,假设要执行一段 Lua 代码并捕获里面出现的所有错误…...

智能进化论:AI必须跨越的四大认知鸿沟
1. 智能缺口:AI进化中的四大认知鸿沟 1.1 理解物理世界:从像素到因果的跨越 想象一个AI看着一杯倒下的水,它能描述“水滴形状”却无法预测“桌面会湿”。这正是当前AI的典型困境——缺乏对物理世界的因果理解。主流模型依赖海量图像或视频数…...
L2-056 被n整除的n位数 - java
L2-056 被n整除的n位数 语言时间限制内存限制代码长度限制栈限制Java (javac)400 ms512 MB16KB8192 KBPython (python3)400 ms256 MB16KB8192 KB其他编译器400 ms64 MB16KB8192 KB 题目描述: “被 n n n 整除的 n n n 位数”是这样定义的:记这个 n n…...

传统足浴行业数字化转型:线上预约平台的技术架构与商业逻辑
上门按摩服务系统开发正成为行业新风口,这绝不是盲目跟风而是实实在在的市场趋势。随着现代人生活节奏加快,时间成本越来越高,传统到店消费模式已经无法满足消费者对便捷服务的需求。我们的团队深耕上门按摩系统开发领域五年,深刻…...
Java-IO流之字节输入流详解
Java-IO流之字节输入流详解 一、Java IO体系与字节输入流概述1.1 Java IO体系结构1.2 字节输入流的核心类层次1.3 字节输入流的基本工作模式 二、InputStream类的核心方法2.1 int read()2.2 int read(byte[] b)2.3 int read(byte[] b, int off, int len)2.4 long skip(long n)2…...

从OCR到Document Parsing,AI时代的非结构化数据处理发生了什么改变?
智能文档处理:非结构化数据提出的挑战 在这个时代的每一天,无论是个人处理账单,还是企业处理合同、保险单、发票、报告或成堆的简历,我们都深陷在海量的非结构化数据之中。这类数据不像整齐排列的数据库表格那样规整,…...
【C/C++】入门grpc的idl
文章目录 grpc idl 简单介绍1. 文件结构组织规范文件命名包结构:推荐:一个文件只定义一个 service,如果 service 很复杂,可拆分多个 proto 文件。 2. 消息定义规范命名风格字段编号:示例: 3. 服务与 RPC 设…...
【Java实用工具类】手撸SqlBuilder工具类,优雅拼接动态SQL,MyBatisPlus同款风格!
📌 正文: 有时候我们项目底层是 JdbcTemplate 查询,没法像 MyBatisPlus 一样用 Wrapper 拼接条件,但我们又不想手撸字符串。那怎么办?我今天就给你整了个 SqlBuilder 工具类,支持 eq、ne、like、in、gt、l…...
宇树科技更名“股份有限公司”深度解析:机器人企业IPO前奏与资本化路径
从技术落地到资本跃迁,拆解股改背后的上市逻辑与行业启示 核心事件:股改释放的上市信号 2025年5月28日,杭州宇树科技有限公司正式更名“杭州宇树科技股份有限公司”,市场主体类型变更为“股份有限公司”。尽管官方称为常规运营调…...

Inno Setup 安装向导各个页面详解
概览 表中描述了使用Inno Setup生成的安装包在安装过程中各个页面的字段和对应的说明信息。后文会对各个页面的参数做进一步解释说明。 字段说明wpWelcome欢迎页wpLicense许可协议wpPassword密码wpInfoBefore信息wpUserInfo用户信息wpSelectDir选择目标位置wpSelectComponent…...
转战web3远程工作的英语学习的路线规划
目录 一、明确学习目标与定位 二、基础阶段(0 - 6个月) (一)词汇积累 (二)语法学习 (三)听力与口语 三、进阶阶段(6 - 18个月) (一…...

OPENCV重点结构体Mat的讲解
一、Opencv的作用 OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 它轻量级而且高效——由一系列 C 函数和少量 C 类构成,同时提供了Pytho…...
Java 创建线程池的几种方式
在 Java 中创建线程池主要通过 java.util.concurrent 包下的 ExecutorService 接口及其实现类。以下是创建线程池的几种常见方式: ✅ 1. 使用 Executors 工具类(最简单) ExecutorService executor Executors.newFixedThreadPool(10);常用方…...

【趣味Html】第11课:动态闪烁发光粒子五角星
打造炫酷的动态闪烁发光粒子五角星效果 前言 在现代Web开发中,视觉效果的重要性不言而喻。今天我们将深入探讨如何使用HTML5 Canvas和JavaScript创建一个令人惊艳的动态闪烁发光粒子五角星效果。这个项目不仅展示了Canvas的强大功能,还涉及了粒子系统、…...
AnyIO Event:异步编程中的同步利器
在异步编程的世界里,任务之间的通信和协调是一个常见的需求。AnyIO 提供的 Event 类,为这一需求提供了一个强大而简洁的解决方案。本文将深入探讨 anyio.Event 的使用方法、特点以及在实际应用中的最佳实践。 一、AnyIO Event 概述 anyio.Event 是 Any…...

CFTel:一种基于云雾自动化的鲁棒且可扩展的远程机器人架构
中文标题: CFTel:一种基于云雾自动化的鲁棒且可扩展的远程机器人架构 英文标题: CFTel: A Practical Architecture for Robust and Scalable Telerobotics with Cloud-Fog Automation 作者信息 Thien Tran, Jonathan Kua, Minh Tran, Hongh…...

Educational Codeforces Round 179 (Rated for Div. 2)
CF2111,简单手速场 A. Energy Crystals 贪心,每次最小值会乘2,直接模拟即可,复杂度 O ( log n ) O(\log n) O(logn) void solve(){int x;cin>>x;multiset<int> s{0,0,0};int res0;while(*s.begin()<x){int x*s.begin();s…...

完成一个可交互的k8s管理平台的页面开发
使用deepseek完成设计一个k8s管理平台,关键词如下: 完成一个可交互的k8s管理平台的页面开发Kubernetes 管理平台页面设计 下面是一个基于现代Web技术的可交互Kubernetes管理平台的页面设计方案,使用React作为前端框架,配合Ant De…...
多线程编程技术解析及示例:pthread_cond_timedwait、pthread_mutex_lock 和 pthread_mutex_trylock
多线程编程技术解析及示例:pthread_cond_timedwait、pthread_mutex_lock 和 pthread_mutex_trylock 摘要 本文深入解析了多线程编程中 pthread_cond_timedwait、pthread_mutex_lock 和 pthread_mutex_trylock 三个函数的功能、使用场景及注意事项,并通…...
vue实现点击单选或者多选模式
toggleSelect(item) { if (!this.single) { // 多选模式 const itemIndex this.selectedItems.findIndex( (selectedItem) > selectedItem.userId item.userId ); // 假设每个对象都有一个唯一的id属性 if (itemIndex ! -1) { this.selectedItems.splice(itemIndex, 1); }…...

Windows系统工具:WinToolsPlus 之 SQL Server 日志清理
使用软件时提示数据库事务日志已满, 使用WinToolsPlus 数据库页签 先设置 数据源 , 选择 需要清理日志的数据库, 点击 数据库日志清理 即可。 下载地址: http://v.s3.sh.cn/archives/2279.html...

在Windows11上安装 Ubuntu WSL
不想安装虚拟机,想在Windows11上运行Linux。网上虽有教程,但是图片明显都是老图,与Windows11还是有些差异。网上缺乏一个齐全的真正的Windows11运行Linux的教程。 一、在Windows上的设置 1. 在window11的搜索框内(所有你找不到的应用都可以用这个搜索功能),搜索&q…...

嵌入式Linux之RK3568
系统烧写镜像。 1、直接使用正点原子官方的updata.img(MIDP) 进入瑞芯微发开工具RKDevTool,选择升级固件,上传到固件,记住这里要进入maskrom模式或者是loader模式,进入该模式之后点击升级即可。 2、烧入自己制作的镜像(单独、一…...
Elasticsearch的插件(Plugin)系统介绍
Elasticsearch的插件(Plugin)系统是一种扩展机制,允许用户通过添加自定义功能来增强默认功能,而无需修改核心代码。插件可以提供从分析器、存储后端到安全认证、机器学习等各种功能,使Elasticsearch能够灵活适应不同的应用场景和业务需求。 一、插件的核心特点 模块化扩展…...
提取 PDF 文件中的文字以及图片中的文字
Adobe 提供了多种方案可以快速提取 PDF 文件中的文字以及图片中的文字,主要依赖其 Acrobat 系列产品和 OCR(光学字符识别)技术。以下是具体解决方案的概述,涵盖了文字和图片文字的提取方法: 1. 提取 PDF 中的文字 如果…...