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

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


二叉树-堆

  • 一、树的概念及结构
    • 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)


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

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

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

相关文章

【C++】——入门基础知识超详解

目录 ​编辑 1.C关键字 2. 命名空间 2.1 命名空间定义 2.2 命名空间使用 命名空间的使用有三种方式&#xff1a; 注意事项 3. C输入&输出 示例 1&#xff1a;基本输入输出 示例 2&#xff1a;读取多个值 示例 3&#xff1a;处理字符串输入 示例 4&#xff1a;读…

Python并发编程大揭秘:打造你的多任务处理超能战队!

今天给大家带来的是学习如何构建一个能够同时处理海量任务的超级团队。从简单的线程和锁&#xff0c;到复杂的异步IO和多进程部署&#xff0c;每一个工具都像是你团队中的一员&#xff0c;各有所长&#xff0c;共同协作&#xff01; 文章目录 Python进阶之并发和并行编程详解1.…

【Linux-INPUT输入的子系统】

Linux-INPUT输入的子系统 ■ input 子系统简介■ input 驱动编写流程■ ■ input 子系统简介 input 子系统就是管理输入的子系统&#xff0c; input 子系统分为 input 驱动层、 input 核心层、 input 事件处理层&#xff0c;最终给用户空间提供可访问的设备节点 ■ input 驱…

leetcode打卡#day39 738. 单调递增的数字

738. 单调递增的数字 class Solution { public:int monotoneIncreasingDigits(int N) {string strNum to_string(N);// flag用来标记赋值9从哪里开始// 设置为这个默认值&#xff0c;为了防止第二个for循环在flag没有被赋值的情况下执行int flag strNum.size();for (int i …

【Linux-中断】

Linux-中断 ■■■ ■■■ ■■■ ■ ■ ■ ■ ■ ■ ■ ■ ■

React类组件生命周期详解

在React的类组件中&#xff0c;从组件创建到组件被挂载到页面中&#xff0c;这个过程react存在一系列的生命周期函数&#xff0c;最主要的生命周期函数是componentDidMount、componentDidUpdate、componentWillUnmount 生命周期图例如下 1. componentDidMount组件挂载 如果你…

S1E45:单链表1 课后作业

测试题&#xff1a;0. 相比起数组来说&#xff0c;单链表具有哪些优势呢&#xff1f; 答&#xff1a;长度非固定&#xff0c;可以申请添加长度 答案&#xff1a;对于数组来说&#xff0c;随机插入或者删除其中间的某一个元素&#xff0c;都是需要大量的移动操作&#xff0c;而…

网络攻击攻击之-远程命令执行/RCE告警运营分析篇

在各种网络安全产品的告警中,远程命令执行是一种非常常见的告警。本文将从远程命令执行的定义,远程命令执行利用的流量数据包示例,远程命令执行的suricata规则,远程命令执行的告分析警研判,远程命令执行的处置建议等几个方面阐述如何通过IDS/NDR,态势感知等流量平台的远程…

深入解析RPC技术:原理、实现与应用

RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;是一种计算机通信协议&#xff0c;允许一个程序&#xff08;客户端&#xff09;在本地调用另一个程序&#xff08;服务器&#xff09;中的函数或方法&#xff0c;并获取返回结果&#xff0c;就像调用…

栈和队列的区别

栈和队列是两种常用的数据结构&#xff0c;它们在数据的存取方式、适用场景和基本操作上有显著的区别。以下是它们的详细区别&#xff1a; 1. 存取方式 栈&#xff08;Stack&#xff09;&#xff1a; 后进先出&#xff08;LIFO, Last In First Out&#xff09;&#xff1a;最…

C++:STL简介和容器string用法篇

一、STL简介 STL是C中的标准模板库&#xff08;Standard Template Library&#xff09;的缩写。它是C标准库的一部分&#xff0c;提供了一系列的数据结构和算法模板&#xff0c;包括各种容器、算法、迭代器、仿函数等&#xff0c;用于简化和加速C程序的开发过程。STL的设计理念…

人形机器人建模与控制(二) - 高级运动学和动态建模

L2: Advanced Kinematic and Dynamic Modeling 这里写目录标题 L2: Advanced Kinematic and Dynamic Modeling1. Introduction2. Kinematic Modeling运动学方程速度的雅可比矩阵雅可比矩阵的两种形式分析雅可比矩阵&#xff08;Analytical Jacobian&#xff09;几何雅可比矩阵&…

【波点音乐看广告】

import uiautomator2 as u2 import time from datetime import datetime import xml.etree.ElementTree as ET import re import os 连接设备 d u2.connect() os.system(‘adb shell chmod 775 /data/local/tmp/atx-agent’) os.system(‘adb shell /data/local/tmp/atx-age…

2024年5月系统架构设计师综合知识真题

1.操作系统:先来先服务调度算法 2.操作系统:多道程序设计&#xff0c;利用率 3.操作系统:状态流转错误的&#xff0c;等待态到运行态 4.数据库:2NF 每一个非主属性完全依赖主键 5.数据库:笛卡尔积m*n 6.数据库:不属于事务的特点&#xff0c;并发性 7.数据库:交集表达式:R-(R-S)…

linux设置不记录历史命令

我们知道Linux历史命令是被保存在内存和各用户家目录下.bash_history文件中&#xff0c;当退出或者登录shell时&#xff0c;其会自动保存或读取。 [rootlogstash ~]# cat .bash_history | tail -n 10 man read touch read.sh chmod 755 read.sh clear vi read.sh sh read.sh…

shell脚本开发基础

shell脚本开发基础 什么是linux内置命令&#xff1f;什么是外置命令 内置命令&#xff1a;在系统启动时就加载入内存&#xff0c;常驻内存&#xff0c;执行效率更高&#xff0c;但是占用资源&#xff0c;cd 外置命令&#xff1a;系统需要从硬盘中读取程序文件&#xff0c;再读…

Fortran: fypp预处理工具

Fortran fypp预处理工具 Fypp基于Python的预处理器工具&#xff0c;不限于语言。利用Python语言&#xff0c;可以批量生成源码 示例 M_logger.fpp module M_loggeruse stdlib_loggeruse stdlib_error contains#:for x,y in [(info,log_information),(debug,log_debug),(warn…

第八篇【传奇开心果系列】Python微项目技术点案例示例:以微项目开发为案例,深度解读Dearpygui 编写图形化界面桌面程序的优势

传奇开心果博文系列 系列博文目录Python微项目技术点案例示例系列 博文目录前言一、开发图形化界面桌面程序的优势介绍二、跨平台特性示例代码和解析三、高性能特性示例代码和解析四、简单易用特性示例代码和解析五、扩展性强示例代码和解析六、现代化设计示例代码和解析七、知…

什么是云渗透测试?

推荐阅读&#xff1a; 什么是安全态势&#xff1f; 什么是人肉搜索 什么是恶意软件&#xff1f; 什么是数字取证&#xff1f; 什么是语音网络钓鱼&#xff1f; 什么是网络安全中的社会工程&#xff1f; 什么是网络安全中的威胁情报&#xff1f; 什么是端点检测和响应 (…

linux 阿里云服务器安装ImageMagick和php扩展imagick

操作系统版本 Alibaba Cloud Linux 3.2104 LTS 64位 # 1.安装ImageMagick yum install -y ImageMagick ImageMagick-devel # 没有pecl要先安装pecl 和头文件 sudo yum install php-devel # 2.pecl 安装扩展 pecl install imagick #寻找所有php.ini文件 find / -name php.…