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

【数据结构】二叉树-堆(上)

在这里插入图片描述
个人主页~


二叉树-堆

  • 一、树的概念及结构
    • 1、概念
    • 2、相关概念
    • 3、树的表示
    • 4、树的实际应用
  • 二、二叉树的概念和结构
    • 1、概念
    • 2、特殊二叉树
    • 3、二叉树的性质
    • 4、二叉树的存储结构
      • (1)顺序存储
      • (2)链式存储
  • 三、二叉树的顺序结构以及实现
    • 1、二叉树的顺序结构
    • 2、堆的概念及结构
      • (1)小根堆
      • (2)大根堆
    • 3、堆的实现
      • (1)堆的向上调整算法--堆的创建
        • ①一般方法
        • ②向上调整建堆
      • (2)向上调整算法的时间复杂度
      • (3)向下调整算法维护堆
      • (4)向下调整算法的时间复杂度

一、树的概念及结构

在我们学习二叉树之前,我们先要了解一下树的概念,二叉树就是一种树
在这里插入图片描述

1、概念

树是一种非线性的数据结构,它是由n个有限节点组成一个具有层次关系的集合,因为根据它所画出的抽象图看起来像一棵倒挂着的树,它的根朝上,树叶朝下

一棵树最顶上的节点叫做根节点,一棵树有且只有一个根节点,根节点没有前驱节点也就是说根节点上面就没有节点了

除了根节点以外,其余节点被分成N个互不相交的集合,我们形象的来说,就是一棵树的叶子和树枝是多对一的概念,也就是说一个树枝可以有多个叶子或者没有叶子,但是一个叶子只能长在一个树枝上,一条小树枝只能长在一条大树枝上,所以树是递归定义的

2、相关概念

节点的度:一个节点含有子树的个数(A的度是3,C的度是0)

叶节点(终端节点):度为0的节点称为叶节点(GHIJKL)

分支节点(非终端节点):度不为0的节点(ABDF)

子节点:一个节点含有的子树的根结点(B是A的子节点)

父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点(A是B的父节点)

兄弟节点:这里的兄弟指的是亲兄弟,也就是具有相同父节点的节点(BCD是兄弟节点)

树的度:整棵树的度是这棵树中的节点的度中最大的那个度(这棵树最大是3)

节点的层次:根为第一层,根的子节点为第二层,子节点的子节点为第
三层,以此类推(第一层:A;第二层:BCD;第三层:FGHI;第四层:JKL)

树的高度(深度):树中节点的最大层次(四层)

堂兄弟节点:父亲为同一层的节点(HI)

节点的祖先:从根到该节点所经分支上的所有节点(J节点的祖先是ABF)

子孙:以某节点为根的子树中任意节点都称为该节点的子孙(B-L都是A的子孙)

森林:由N棵(N>0)互不相交的树组成的集合称为森林

树的概念都是由人类的亲缘关系决定的,我们在记忆的时候可以结合我们人类的亲缘关系来记忆

3、树的表示

树的表示方法有很多种,如果我们再像以前一样定义一个结构体,其中存放指针和数据,那样就不行了,因为我们不知道一个节点有多少子树,这样就没办法定义树的节点的结构体,这里,我们有一个最好的办法就是左孩子右兄弟法

左孩子右兄弟法:

typedef int DataType;
struct Node
{struct Node* _firstChild1; // 第一个孩子结点,也就是最左边的孩子struct Node* _pNextBrother; // 指向其下一个兄弟结点,就是右边第一个兄弟DataType _data; // 结点中的数据域
};

左孩子右兄弟法就是一个指针指向左边第一个孩子,右指针指向右边第一个兄弟
在这里插入图片描述
图画的不太好看,将就一下
红色的线是左孩子
蓝色的线是右兄弟
这样我们可以简洁并且快速地找到这棵树所有的分支

4、树的实际应用

文件系统的目录就是树的应用
在这里插入图片描述
E盘:
在这里插入图片描述
这里就是树的应用,文件系统的目录是用树的结构实现的

二、二叉树的概念和结构

1、概念

二叉树就是在树的基础上加上特殊
二叉树是由一个根节点加上一个左子树和一个右子树组成的
二叉树不存在度大于2的节点
二叉树是有序树,因为它的子树有左右之分,次序不能颠倒

2、特殊二叉树

(1)满二叉树
一个二叉树,如果每一个层的节点数都达到最大值,那么这个二叉树就是满二叉树
在这里插入图片描述

(2)完全二叉树
完全二叉树是效率很高的二叉树,它的最后一层可以不满,最后一层之前的层都是满的,然后最后一层的节点是需要按序排列的,满二叉树是一种特殊的完全二叉树
在这里插入图片描述

3、二叉树的性质

若规定根节点的层数为1,具有n个节点的满二叉树的深度h=log₂(n+1)

对于具有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,否则无右孩子

4、二叉树的存储结构

二叉树有两种存储结构,一种是顺序存储,另一种是链式存储

(1)顺序存储

顺序存储就是使用数组来存储,一般只适合表示完全二叉树,因为不是完全二叉树会有空间上的浪费,二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树

(2)链式存储

链式存储就是使用链表来存储,通常的方法是链表节点由三个域组成,分别是数据域以及左右指针域,左右指针存储左右孩子的地址

链式结构又分为二叉链和三叉链,这里使用的是二叉链

typedef int BTDataType;
// 二叉链
struct BinaryTreeNode
{struct BinTreeNode* Left; // 指向左孩子struct BinTreeNode* Right; // 指向右孩子BTDataType data; // 值域
};// 三叉链
struct BinaryTreeNode
{struct BinTreeNode* Parent; // 指向父节点struct BinTreeNode* Left; // 指向左孩子struct BinTreeNode* Right; // 指向右孩子BTDataType data; // 值域
};

三、二叉树的顺序结构以及实现

1、二叉树的顺序结构

现实中我们经常把堆(一种二叉树)使用顺序结构的数组来存储,这里的堆与malloc位置的堆的概念是不同的,malloc位置的堆是操作系统中的内存管理,这里的堆是我们人为实现的一种数据结构

2、堆的概念及结构

把一堆数据按照完全二叉树的顺序存储方式存储在一个一维数组中,并且满足第i项第2i+2项,i为自然数,则称为堆,根节点最大的堆叫大堆(大根堆),根节点最小的堆叫小堆(小根堆)

性质:
①堆总是一颗完全二叉树
②堆中某个节点的值总是不大于或不小于其父节点的值

(1)小根堆

逻辑结构:
在这里插入图片描述
物理结构(存储结构):
在这里插入图片描述

(2)大根堆

逻辑结构:

在这里插入图片描述
物理结构(存储结构):
在这里插入图片描述
这里的存储结构中的数据不一定是有序的,也可以不是升序或者降序,但是大堆的父节点一定比子节点大,小堆的父节点一定比子节点小

3、堆的实现

(1)堆的向上调整算法–堆的创建

①一般方法

我们在使用堆的向下调整算法之前要保证左右子树都要是堆,那么在使用之前我们先要创建堆

我们创建一个数组,在逻辑上可以看做一颗完全二叉树,然后我们通过算法把它构建成为一个堆,从倒数第一个叶子节点开始调整一直到根节点,就可以调整成堆

int arr[] = {1,4,7,2,5,9};

在这里插入图片描述
最后的9与它的父节点7交换:
在这里插入图片描述
1<9再交换
在这里插入图片描述
然后再检查最后一个叶子节点,重复上面的步骤,虽然这样最终可以建立一个堆,但这样效率特别低,所以我们有了向上调整算法来建堆

②向上调整建堆

现在我们有一个数组,在逻辑上看成一棵完全二叉树,我们要创建一个堆,可以用向上调整算法

void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;//因为除法向下取整,所以右孩子也能//因为是一颗完全二叉树,所以父节点总是可以通过子节点减1除以二找到//while (parent >= 0)while (child > 0)//这里用子节点作为循环条件,因为child可能调整到根节点上{if (a[child] > a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}//大于就交换,把此时的父节点变成子节点,父节点的父节点变成父节点,比较上一层的关系else{break;}}
}

从二叉树的根节点的左孩子开始调整,按照下标依次调整,最终会建成一个堆
图演示:
在这里插入图片描述
下标1向上调整:
在这里插入图片描述
下标2向上调整:
在这里插入图片描述
下标3调整两次:(第二次小于7,不调)
在这里插入图片描述
下标4调整两次:(第二次小于7,不调)
在这里插入图片描述

下标5调整两次:
第一次:
在这里插入图片描述
第二次:
在这里插入图片描述
这样就建成一个堆了

(2)向上调整算法的时间复杂度

在这里插入图片描述
设树的高度为h
第1层:2^0个节点,需要向上移动0层
第2层:2^1个节点,需要向上移动1层
第3层:2^2个节点,需要向上移动2层
……
第h-1层:2^(h-2)个节点,需要向上移动h-2层
第h层:2^(h-1)个节点,需要向上移动h-1层
将它们相加
在这里插入图片描述
解得原式=2+2^h*(h-2)

遍历一遍为N = 2^h

去掉不重要的项,得时间复杂度O(N*log₂N)

(3)向下调整算法维护堆

当我们需要将堆顶的数据删除掉,那么这个堆就没有了根,如果再重新进行建堆会浪费很多的时间,这里有一种方法的时间复杂度小于重新建堆,这种算法就是向下调整算法

void AdjustDown(int* a, int n, int parent)//n是数组a的数据个数
{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[parent], &a[child]);parent = child;child = parent * 2 + 1;}//谁大谁是爹else{break;}}
}

(4)向下调整算法的时间复杂度

在这里插入图片描述
设树的高度为h
第1层:2^0个节点,需要向下移动h-1层
第2层:2^1个节点,需要向下移动h-2层
第3层:2^2个节点,需要向下移动h-3层
……
第h-1层:2^(h-2)个节点,需要向下移动1层
第h层:2^(h-1)个节点,需要向下移动0层
将它们相加之后由错位相减法得
2^h-1-h
因为N = 2^h,所以原式=N-1-log₂N

因为当h趋于无穷大时,N远大于log₂N,所以时间复杂度O(N)


今日分享就到这~
在这里插入图片描述

相关文章:

【数据结构】二叉树-堆(上)

个人主页~ 二叉树-堆 一、树的概念及结构1、概念2、相关概念3、树的表示4、树的实际应用 二、二叉树的概念和结构1、概念2、特殊二叉树3、二叉树的性质4、二叉树的存储结构&#xff08;1&#xff09;顺序存储&#xff08;2&#xff09;链式存储 三、二叉树的顺序结构以及实现1、…...

【Spring Boot】在项目中使用Spring AI

Spring AI是Spring框架中用于集成和使用人工智能和机器学习功能的组件。它提供了一种简化的方式来与AI模型进行交互。下面是一个简单的示例&#xff0c;展示了如何在Spring Boot项目中使用Spring AI。 步骤 1: 添加依赖 首先&#xff0c;在pom.xml文件中添加Spring AI的依赖&…...

【java程序设计期末复习】chapter3 运算符、表达式和语句

运算符、表达式和语句 Java提供了丰富的运算符&#xff0c;如算术运算符、关系运算符、逻辑运算符、位运算符等。 Java语言中的绝大多数运算符和C语言相同&#xff0c;基本语句&#xff0c;如条件分支语句、循环语句等也和C语言类似&#xff0c;因此&#xff0c;本章就主要知识…...

【建议收藏】30个较难Python脚本,纯干货分享

本篇较难&#xff0c;建议优先学习上篇 &#xff1b;20个硬核Python脚本-CSDN博客 接上篇文章&#xff0c;对于Pyhon的学习&#xff0c;上篇学习的结束相信大家对于Pyhon有了一定的理解和经验&#xff0c;学习完上篇文章之后再研究研究剩下的30个脚本你将会有所成就&…...

01-05.Vue自定义过滤器

目录 前言过滤器的概念过滤器的基本使用给过滤器添加多个参数 前言 我们接着上一篇文章01-04.Vue的使用示例&#xff1a;列表功能 来讲。 下一篇文章 02-Vue实例的生命周期函数 过滤器的概念 概念&#xff1a;Vue.js 允许我们自定义过滤器&#xff0c;可被用作一些常见的文本…...

C++系列-static成员

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 概念 声明为static的类成员称为类的静态成员&#xff0c;用static修饰的成员变量&#xff0c;称之为静态成员变量&#xff0c;用static修饰的成员函数&#xff0c;称之为静态成…...

Git | 创建和管理Pull Request总结

如是我闻&#xff1a; 在使用 GitHub 进行项目协作时&#xff0c;掌握如何创建、更新和合并&#xff08;squash&#xff09;pull request 是非常有帮助的。本文将详细介绍这些操作&#xff0c;帮助我们更好地管理项目代码&#xff0c;并解释每个操作的原因和解决的问题。 1. 什…...

电机控制系列模块解析(23)—— 同步机初始位置辨识

一、两个常见问题 为什么感应电机&#xff08;异步机&#xff09;不需要初始位置辨识&#xff1f;&#xff08;因此感应电机转子磁场在定子侧进行励磁&#xff0c;其初始位置可以始终人为定义为0&#xff09; 为什么同步磁阻电机需要初始位置辨识&#xff1f;&#xff08;因为…...

【数据库基础-mysql详解之索引的魅力(N叉树)】

索引的魅力目录 &#x1f308;索引的概念&#x1f308;使用场景&#x1f308;索引的使用&#x1f31e;&#x1f31e;&#x1f31e;查看MySQL中的默认索引&#x1f31e;&#x1f31e;&#x1f31e;创建索引&#x1f31e;&#x1f31e;&#x1f31e;删除索引 站在索引背后的那个男…...

力扣739. 每日温度

Problem: 739. 每日温度 文章目录 题目描述思路复杂度Code 题目描述 思路 若本题目使用暴力法则会超时&#xff0c;故而使用单调栈解决&#xff1a; 1.创建结果数组res&#xff0c;和单调栈stack&#xff1b; 2.循环遍历数组temperatures&#xff1a; 2.1.若当stack不为空同时…...

KDE6桌面于2024年2月发布

原文&#xff1a;KDE MegaRelease 6 - KDE 社区 1. **Plasma 6 桌面环境**&#xff1a;KDE Plasma 是一个现代化、功能丰富的 Linux 操作系统桌面环境&#xff0c;以其时尚设计、可定制界面和广泛的应用程序而闻名。Plasma 6 带来了两项重大技术升级&#xff1a;过渡到最新的应…...

「TypeScript系列」TypeScript 对象及对象的使用场景

文章目录 一、TypeScript 对象1. 对象字面量2. 类实例化3. 使用接口定义对象形状4. 使用类型别名定义对象类型5. 使用工厂函数创建对象 二、TypeScript 对象属性及方法1. 对象属性2. 对象方法3. 访问器和修改器&#xff08;Getters 和 Setters&#xff09; 三、TypeScript 对象…...

shell从入门到精通(22)shell正则匹配~=

文章目录 1. 基本用法2. 正则表达式捕获组(catch group)3. 匹配结果提取1. 基本用法 在 Shell 脚本中,可以使用正则表达式进行文本匹配和提取。Bash shell 支持使用 [[ … =~ … ]] 结构进行正则表达式匹配,同时还能提取匹配结果。 以下是一个简单的例子,展示了如何在 Bas…...

【Spring】使用Spring常用导入依赖介绍

当使用Spring框架时&#xff0c;以下是常用导入的依赖的详细介绍&#xff0c;按照不同的功能和类别进行分点表示和归纳&#xff1a; 1、核心依赖 Spring Core (spring-core) 功能&#xff1a;提供了Spring框架的基础功能&#xff0c;包括IoC&#xff08;控制反转&#xff09;…...

PC端应用订阅SDK接入攻略

本文档介绍了联想应用联运sdk接入操作指南&#xff0c;您可在了解文档内容后&#xff0c;自行接入应用联运sdk。 1. 接入前准备 1. 请先与联想商务达成合作意向。 2. 联系联想运营&#xff0c;提供应用和公司信息&#xff0c;并获取商户id、app id、key&#xff08;公私钥、…...

WebService的wsdl详解

webservice服务的wsdl内容详解&#xff0c;以及如何根据其内容编写调用代码 wsdl示例 展示一个webservice的wsdl&#xff0c;及调用这个接口的Axis客户端 wsdl This XML file does not appear to have any style information associated with it. The document tree is shown…...

数据分析实战:从0到1完成数据获取分析到可视化

文章目录 1.数据分析基本流程1.1 数据采集1.2 数据提炼1.3 数据探索分析 2.数据获取的方法和工具2.1 数据解锁器2.2 爬虫浏览器2.3 数据洞察市场 3.完整案例分析&#xff1a;从数据采集到数据可视化3.1 直接按需定制数据集获取数据3.2 获取IP代理&#xff0c;利用python爬取数据…...

【Spring】深入理解 Spring 中的 ImportSelector、Aware 和 Processor 接口

前言 Spring 框架提供了一系列接口和机制&#xff0c;为开发者提供了灵活、可扩展的编程模型。其中&#xff0c;ImportSelector、Aware 接口以及 Processor 系列接口是非常重要的扩展点&#xff0c;本文将深入探讨它们的设计目的、使用方法以及示例应用。 一、ImportSelector…...

【C语言】strstr函数的使用和模拟

前言 今天给大家带来一个字符串函数&#xff0c;strstr()的使用介绍和模拟实现。 模拟实现这个函数&#xff0c;可以帮助我们更深刻地理解这个函数的功能和提高解决字符串相关问题的能力&#xff0c;有兴趣的话就请往下看吧。 strstr函数介绍 函数功能&#xff1a; strstr函…...

五分钟”手撕“异常

目录 一、什么是异常 二、异常的体系和分类 三、异常的处理 1.抛出异常 2.异常的捕获 异常声明throws&#xff1a; try-catch处理 四、finally finally一定会被执行吗&#xff1f; 五、throw和throws区别 六、异常处理的流程 七、自定义异常 一、什么是异常 顾名…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...