当前位置: 首页 > news >正文

数据结构——二叉树(2)

接上一篇文章http://t.csdnimg.cn/nsKsW,本次我们接着讲解关于二叉树的相关知识。

一、二叉树的相关性质:

1. 若规定根节点的层数为 1 ,则一棵非空二叉树的 i 层上最多有 2^(i-1) 个结点.
2. 若规定根节点的层数为 1 ,则 深度为 h 的二叉树的最大结点数是 2^(h-1)
3. 对任何一棵二叉树 , 如果度为 0 其叶结点个数为n0  , 度为 2 的分支结点个数为n1  , 则有n0=n1+1
4. 若规定根节点的层数为 1 ,具有 n 个结点的满二叉树的深度h=
5. 对于具有 n 个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从 0 开始编号,则对于序号为i 的结点有:
①. i>0 i 位置节点的双亲序号为: (i-1)/2 i=0; i 为根节点编号,无双亲节点
②. 2i+1<n ,左孩子序号: 2i+1; 2i+1>=n 否则无左孩子
③. 2i+2<n ,右孩子序号: 2i+2; 2i+2>=n 否则无右孩子
6.通过孩子找双亲:设孩子的编号为i,则其双亲的编号为A=(i-1)/2;根节点没有双亲;

二、二叉树的存储结构:

(一)、顺序储存(数组)

1.顺序结构存储就是使用 数组来存储 ,一般使用数组 只适合表示完全二叉树 ,因为不是完全二叉树会有空间的浪费。而现实中使用中只有 才会使用数组来存储,关于堆我们后面的章节会专门讲解。二叉树顺 序存储在物理上是一个数组,在逻辑上是一颗二叉树。
根据上述有几点性质:
2. 对于具有 n 个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从 0 开始编号,则对于序号为i 的结点有:
①. i>0 i 位置节点的双亲序号为: (i-1)/2 i=0; i 为根节点编号,无双亲节点
②. 2i+1<n ,左孩子序号: 2i+1; 2i+1>=n 否则无左孩子
③. 2i+2<n ,右孩子序号: 2i+2; 2i+2>=n 否则无右孩子
3.通过孩子找双亲:设孩子的编号为i,则其双亲的编号为A=(i-1)/2;根节点没有双亲;
4.满二叉树或者完全二叉树适合用顺序存储,而非完全二叉树适合用链式存储;

(二)、衍生数据结构——堆:

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆 ( 一种二叉树 ) 使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统 虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

1.堆的概念

堆是一种非线性结构,是特殊的完全二叉树,所以适合用数组存储;

2.堆的分类:

小堆(小根堆):树中任意父亲的值都小于等于其孩子;

大堆(大根堆):树中任意父亲的值都大于等于其孩子;

如下图:

(三)、堆的实现(顺序存储)

一般堆我们用顺序存储的方式实现,即用一维数组,所以定义与顺序表差不多,只是实现逻辑不一样,所以基本定义与销毁等操作就大致讲解。

1.堆的定义:
typedef int HPDatatype;
typedef struct Heap
{HPDatatype* a;//一维数组int size;//现有元素个数int capacity;//当前结构最大空间
}HP;
2.堆的初始化:
//初始化
void HPinit(HP* php)
{assert(php);php->size = 0;php->capacity = 0;php->a = NULL;
}
3.堆的销毁
//销毁
void HPDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->size = 0;php->capacity = 0;
}
4.堆的打印:
//打印
void HPprint(HP* php)
{assert(php);for (int i = 0; i < php->size; i++){printf("%d ", php->a[i]);}printf("\n");
}
5.插入数据:

因为堆是特殊的完全二叉树,所以插入算法与顺序表完全不同;

我们以实现小堆为例

①:首先我们应该考虑是否堆满,根据我们定义所示,当size==capacity时即为堆满,此时我们需要进行扩容方式,因为只有此处可能进行扩容,所以不用单独分装成一个函数,扩容方式与之前的顺序表等等结构相似,所以小编不做多余讲解;

②:根据完全二叉树的顺序存储结构来看,我们知道数组的尾元素即为完全二叉树的尾元素,所以我们插入数据只需在数组的尾部进行插入,又因为堆是特殊的完全二叉树,小堆即双亲结点的值比其所有孩子的值要小,所以当数据插入后,还要将数据与其双亲进行比较,若不满足条件,我们要进行数据的交换,而且我们需要循环进行此操作,直到比较完根节点,又因为我们是不断在找双亲,所以我们称这种方法为“向上调整”,向上调整的前提是前面的结构已经是堆结构了。

③:我们既然要找双亲,所以我们需要牢记双亲结点与孩子结点之前的位置关系,即为上述的几条完全二叉树的性质,向上调整具体算法如下图:

④:时间复杂度为O(log以2为底的n),因为插入元素的时间复杂度为O(1),向上调整的最坏情况为调整至根结点,即完全二叉树的高度,为log以2为底的n;

⑤,源代码 

//交换函数
void Swap(HPDatatype* p1, HPDatatype* p2)
{HPDatatype tmp = *p1;*p1 = *p2;*p2 = tmp;
}//向上调整
void AdjustUp(HPDatatype* a, int child)
{int parent = (child - 1) / 2;while (child > 0){//以小堆为例插入数据if (a[parent] > a[child]){//交换位置Swap(&a[parent],&a[child]);//比较完一组后重定位,向上调整child = parent;parent = (parent - 1) / 2;}else{//插入结束break;}}
}//插入元素
void HPPush(HP* php, HPDatatype x)
{assert(php);//扩容if (php->size == php->capacity){php->capacity = (php->capacity == 0 ? 4 : php->capacity * 2);HPDatatype* tmp = (HPDatatype*)realloc(php->a, sizeof(HPDatatype) * php->capacity);//检查扩容if (tmp == NULL){perror("realloc");return;}php->a = tmp;}//插入元素php->a[php->size] = x;//检查是否需要向上调整AdjustUp(php->a, php->size);php->size++;
}
6.删除数据:

首先我们考虑一个问题,删除哪个元素有意义呐?

很明显,删除根节点最有意义,因为在大堆中,根节点是最大值;在小堆中,根节点是最小值;所以删除根节点比较有意义一些;

很多小伙伴可能会想,“删除根结点无非就是将数组元素挪动直接覆盖嘛”,答案是不行的,因为我们要清楚一点,堆结构只是孩子与双亲有关系,但孩子之间和兄弟之间是没有关系的,所以挪动数据覆盖元素可能会导致孩子或者兄弟错位,从而覆盖后可能就不是堆结构了;

下面介绍一种思路:上面插入数据用到“向上调整”,现在我们删除数据就用到“向下调整”;

向下调整思路(以小堆结构为例)

①:先交换根结点和尾结点的值;

②:删除尾结点(数组总元素size减1)

③:再找出根结点的两个孩子中较小的孩子,然后交换双亲与较小孩子的值;

④:接着对双亲和孩子重定位,依次向下调整;

注意:其中很多细节应当尤其注意,如可能有些情况没有右孩子等等,具体思路看注释;

//向下调整
void AdjustDown(HPDatatype* a, int n, int parent)
{int child = parent * 2 + 1;while (child<n){//找出小孩子,同时要注意有没有右孩子,防止child+1越界if (a[child] > a[child + 1]&&child+1<n){child++;}//交换if (a[child] < a[parent]){Swap(&a[child], &a[parent]);//继续向下调整parent = child;child = parent * 2 + 1;}else{break;}}
}//删除元素
void HPPop(HP* php)
{assert(php);//判断堆空assert(php->size > 0);//交换首尾结点Swap(&php->a[0], &php->a[php->size - 1]);//删除尾结点,因为是数组,所以直接将现有元素size-1不访问即可--php->size;//向下调整AdjustDown(php->a, php->size, 0);
}

7.取堆顶元素(取根节点)

//取堆顶(取根结点)
HPDatatype HPTop(HP* php)
{assert(php);//判断是否为堆空assert(php->size > 0);return php->a[0];
}

8.判空

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

本文章未完待续

相关文章:

数据结构——二叉树(2)

接上一篇文章http://t.csdnimg.cn/nsKsW&#xff0c;本次我们接着讲解关于二叉树的相关知识。 一、二叉树的相关性质&#xff1a; 1. 若规定根节点的层数为 1 &#xff0c;则一棵非空二叉树的 第 i 层上最多有 2^(i-1) 个结点. 2. 若规定根节点的层数为 1 &#xff0c;则 深度…...

aosp定制android系统

目录 AOSP 准备工作(配置) 确定机型和版本 初始化 git安装 curl安装 同步源码 环境变量 创建aosp目录 指定同步版本 解下来安装编译需要的依赖 编译aosp源码 刷入系统 AOSP 全称 Android Open Source Project 是指Android开源项目&#xff0c;它是由Google主导的…...

程序员的护城河:构建数字世界的守护者

目录 前言1 持续学习的愿望和能力2 与他人沟通和合作的能力3 追求技术的深度和广度4 具备分享的精神结语 前言 在数字化时代&#xff0c;程序员是现代社会的护城河。他们的工作不仅是构建应用程序和系统&#xff0c;更是为保障系统安全、数据防护以及网络稳定发挥着至关重要的…...

Sample Average Approximation,SAA

1. sample average approximation,SAA “样本平均近似”&#xff08;Sample Average Approximation&#xff0c;SAA&#xff09;方法是数学优化和运筹学领域广泛使用的优化技术。它主要用于处理优化问题的目标函数或约束涉及随机或不确定参数的情况。SAA尤其适用于具有随机或概…...

springbootMysql文华学院青年志愿者服务预约系统97973-计算机毕业设计项目选题推荐(附源码)

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 文华学院青年志愿者服务预约系统&#xff0c;主要的模块包括管理员&#xff1a;后台首页、轮播图、通知公告管理、资源管理&#xff08;新闻资…...

Go 语言向函数传递数组

Go 语言向函数传递数组 在 Go 语言中&#xff0c;数组是值类型&#xff0c;因此将数组传递给函数时&#xff0c;将复制整个数组。如果数组非常大&#xff0c;这可能会导致性能问题。为了避免复制整个数组&#xff0c;可以通过传递切片&#xff08;Slice&#xff09;来传递数组…...

高压放大器在铁电测试中的用途有哪些

高压放大器在铁电测试中有多种重要用途。铁电材料是指具有自发极化的晶体材料&#xff0c;具有一系列特殊的电学和物理性质。铁电测试是研究铁电材料性质的关键实验手段之一。下面安泰电子将介绍高压放大器在铁电测试中的几个主要用途。 极化场施加&#xff1a;铁电材料的最显著…...

一款高效、简洁的数据处理和清洗加工工具,值得收藏!

随着数字化时代的快速发展&#xff0c;数据已经成为企业运营和决策的重要依据。然而&#xff0c;处理和分析大量复杂数据是一个具有挑战性的任务&#xff0c;特别是在数据清洗和加工环节。为了满足这一需求&#xff0c;JVS-BI提供了一套高效、简洁的数据处理和分析解决方案。 …...

很多个pdf怎么合并在一起?

很多个pdf怎么合并在一起&#xff1f;作为一个办公室的伙伴&#xff0c;对于PDF格式肯定不会陌生。它强大的功能为我们的工作提供了许多便利。由于PDF文件格式的稳定性和安全性较高&#xff0c;我们通常在工作或学习中使用它来传输文件&#xff0c;很多人都喜欢将办公文件都做成…...

Ubuntu apt更换国内镜像源,apt 更新源,apt 国内镜像

详细一篇&#xff1a; https://midoq.github.io/2022/05/30/Ubuntu20-04%E6%9B%B4%E6%8D%A2%E5%9B%BD%E5%86%85%E9%95%9C%E5%83%8F%E6%BA%90/ 更换方法 Ubuntu采用apt作为软件安装工具&#xff0c;其镜像源列表记录在/etc/apt/source.list文件中。 首先将source.list复制为s…...

时序预测 | MATLAB实现WOA-CNN-BiLSTM-Attention时间序列预测(SE注意力机制)

时序预测 | MATLAB实现WOA-CNN-BiLSTM-Attention时间序列预测&#xff08;SE注意力机制&#xff09; 目录 时序预测 | MATLAB实现WOA-CNN-BiLSTM-Attention时间序列预测&#xff08;SE注意力机制&#xff09;预测效果基本描述模型描述程序设计参考资料 预测效果 基本描述 1.MAT…...

VINS-Mono-后端优化 (一:预积分残差计算-IMU预积分约束)

这里先回顾一下预积分是怎么来的 VINS-Mono-IMU预积分 &#xff08;三&#xff1a;为什么要预积分预积分推导&#xff09; 这里贴出预积分的公式 具体含义解释看对对应的文章 整个误差函数如下 预积分 α \alpha α β \beta β γ \gamma γ 是用 IMU 预积分获得的增量&a…...

怎么调整excel表里面所有单元格中,某个相同字体大小,单元格中其他文字大小不变?

环境: excel 2021 python3.8 问题描述: 怎么调整excel表里面所有单元格里面1这个字体大小,单元格里面其他文字不变? excel表里面。很多单元格都有1,1和文字都是10号字体,现在想把全部1字字体调整为16号其他字大小都不变 解决方案: 一、使用python来实现,经过测…...

流式数据库引擎备受关注,亚信安慧AntDB数据库受邀参加“2023中国PostgreSQL数据库生态大会”

11月3日至5日&#xff0c;2023中国PostgreSQL数据库生态大会在北京中科院软件所大报告厅盛大召开&#xff0c;大会现场百余位专家学者、企业、用户代表及线上数千位观众&#xff0c;就近年来国产数据库技术与市场变革进行深入探讨。湖南亚信安慧科技有限公司&#xff08;简称&a…...

kafka开启SSL认证(包括内置zookeeper开启SSL)

zookeeper和kafka的SSL开启都可单独进行 生成SSL证书 使用jre自带的keytool工具生成&#xff0c;linux和windows下生成的证书可以通用 生成含有一个私钥的keystore文件&#xff0c;有效期10年&#xff08;本文证书密码统一使用test123&#xff09; keytool -genkeypair -ali…...

Powerpoint不小心被覆盖?PPT误删文件如何恢复?

PowerPoint不小心删除了&#xff0c;这可能是众多学生和工作人员最头痛的事情了。PPT被覆盖或误删可能意味着几个小时的努力付之东流。那么PPT覆盖的文档要如何救回来呢&#xff1f;小编将会在本篇文章中为大家分享几个解决方案&#xff0c;使PPT文档覆盖还原操作成为可能&…...

美团产品经理面试题大解密:流量VS口碑,如何找到最佳平衡点?

大家好&#xff0c;我是你们的小米。最近我参加了一场美团的产品经理面试&#xff0c;其中一个问题让我颇为犯愁&#xff1a;“产品应该追求高流量还是高口碑&#xff1f;”这个问题困扰了很多产品经理&#xff0c;因为两者似乎都对产品的成功有着重要影响。今天我就来和大家一…...

docker部署tomcat

1.下载tomcat镜像 尽量去下载最新版本 直接输入docker pull tomcat 后面不跟版本号(要是跟版本号&#xff0c;你还要去官网去查看是否有此版本&#xff0c;太麻烦了) 2.查看镜像 3.通过镜像去run启动容器 -d 就是后台运行 --name 给容器取个新名字 -p 3355:8080…...

大语言模型(LLM)综述(七):大语言模型设计应用与未来方向

A Survey of Large Language Models 前言8 A PRACTICAL GUIDEBOOK OF PROMPT DESIGN8.1 提示创建8.2 结果与分析 9 APPLICATIONS10 CONCLUSION AND FUTURE DIRECTIONS 前言 随着人工智能和机器学习领域的迅速发展&#xff0c;语言模型已经从简单的词袋模型&#xff08;Bag-of-…...

牛客网:链表分割

一、题目 函数原型&#xff1a; ListNode* partition(ListNode* pHead, int x) 二、思路 根据题意&#xff0c;可以设置两个新的链表&#xff0c;将原链表中所有小于x的结点链接到链表1中&#xff0c;大于x的结点链接到链表2中&#xff0c;最后再将两个链表合并即可。 此题有两…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

Webpack性能优化:构建速度与体积优化策略

一、构建速度优化 1、​​升级Webpack和Node.js​​ ​​优化效果​​&#xff1a;Webpack 4比Webpack 3构建时间降低60%-98%。​​原因​​&#xff1a; V8引擎优化&#xff08;for of替代forEach、Map/Set替代Object&#xff09;。默认使用更快的md4哈希算法。AST直接从Loa…...