【数据结构】二叉树的存储结构

news2024/11/19 6:33:59

二叉树的存储结构

  • 导读
  • 一、存储结构
  • 二、顺序存储结构
  • 三、链式存储结构
  • 结语

封面

导读

大家好,很高兴又和大家见面啦!!!

在前面的内容中,我们已经认识了树这种新的数据结构以及二叉树这种特殊的树。

与前面我们学习的线性表不同,在树这种新的数据结构中,数据与数据之间呈现的是一对多和多对一的关系在逻辑上就像一棵树一样从树根开始往外发散式的分布,因此我们将数据之间呈现的这种逻辑关系称为树形结构

而二叉树作为一种特殊的树形结构,二叉树中的数据与数据之间呈现的是一对二和二对一的关系,每一个数据向下都会对应两个数据;同理,每两个数据向上都会对应一个数据。不管是向下还是向上,对于一个数据而言,与它对应的这两个数据可能都为空,也可能是其中一个为空。

在今天的内容中我们将会介绍一下对于二叉树这种特殊的逻辑结构,在物理上又应该如何对这些数据进行存储。

一、存储结构

对于计算机而言,数据在计算机中对树形结构进行存储时,并不可能做到像逻辑结构一样的树形存储,因此在实际的存储过程中,我们只能够像线性表一样将数据以顺序存储或链式存储的方式存入内存中。

这时可能有朋友就会奇怪了,既然不能做到真正的树形存储,为什么会有树这种数据结构呢?

对于这个问题,我个人的理解是——不同的数据结构之间的差异主要体现在对数据的实际操作上。

例如在线性结构中,因为数据在逻辑上是一对一的进行存储的,因此我们在对线性结构中查找数据时,可以通过一个元素找到与它对应的前驱数据和后继数据;而对于树形结构而言,我们则可以通过一个数据找到与其对应的父结点和孩子结点。

在前面的介绍中我们有提到过计算机的内存空间主要是三块分区:

  1. 存储局部变量、函数等数据的栈区
  2. 存储由malloc/calloc这些动态函数申请的动态数据的堆区
  3. 存储像全局变量、静态数据以及常量等数据的静态区

不管是哪一块分区,其内存空间都是一块连续的存储空间,因此数据在实际的存储过程中并不会出现像树形结构这种特殊的结构。而在数据的实际操作过程中,我们则可以根据数据在逻辑上的关系对数据进行增删改查等相关的操作。

在理解了树与线性表的区别后,下面我们就来详细介绍一下二叉树的两种存储结构。

二、顺序存储结构

顺序存储结构我们并不陌生了,所谓的顺序存储就是通过一块地址连续的存储单元来存放数据。

在线性表的顺序存储中,对于逻辑上相邻的两个元素,我们在存储时需要使其在物理位置上也相邻;而在二叉树的顺序存储中,由于数据之间呈现的是一对多和多对一的关系,因此在实际存储中,二叉树中的各个数据在物理位置上不一定相邻。
线性表与二叉树
从上图中可以看到对于线性表而言,因为元素在逻辑上是一对一的关系,因此在进行顺序存储时,每一个元素都能与其逻辑相邻的元素做到物理位置上也相邻;但是在二叉树中,因为元素在逻辑上是一对多的关系,对于元素 a 3 a_3 a3来说,逻辑上与其相邻的有三个元素 a 1 a_1 a1 a 5 a_5 a5 a 6 a_6 a6,但是通过顺序存储的话我们会发现这三个元素是无法做到同时与 a 3 a_3 a3在物理位置上也相邻的。

在这种情况下,我们应该如何来对二叉树中的元素进行顺序存储呢?

在前面我们有提到过,对于不同的数据结构而言,它们的区别主要体现在对数据结构中的数据元素的具体操作上。因此不管是逻辑结构还是存储结构,都是为了能够方便程序猿对这些数据进行相应的操作。

对于二叉树而言,为了体现数据之间的逻辑关系,我们可以通过元素之间的逻辑关系来对其进行顺序存储。在上一篇中我们有介绍过满二叉树和完全二叉树,在这两种二叉树中,如果给每个结点从上到下,从左到右依次进行编号的话,结点与结点的编号之间是存在一定的联系的。

例如,在从0开始编号且结点数量为 n ( n > = 1 ) n(n>=1) n(n>=1) 的完全二叉树中,对于编号为 i i i 的结点与其父结点以及孩子结点的关系如下:

  • 若该结点存在父结点,则其父结点的编号为 ( i − 1 ) / 2 (向下取整) (i-1)/2(向下取整) (i1)/2(向下取整)。若 i i i 为奇数,则该结点为其父结点的左孩子;若 i i i 为偶数,则该结点为其父结点的右孩子;
  • 若该结点存在左孩子,则其左孩子的结点编号为 2 i + 1 ( 2 i + 1 < = n ) 2i+1(2i+1<=n) 2i+1(2i+1<=n);若该结点存在右孩子,则其右孩子的结点编号为 2 i + 2 ( 2 i + 2 < = n ) 2i+2(2i+2<=n) 2i+2(2i+2<=n)

如果将这些结点的编号作为其对应的数组空间的下标,那我们是不是就可以在对这些数据进行顺序存储时,通过其下标来找到与其在逻辑上相邻的各个元素了呢?

因此二叉树的顺序存储指的是通过一块地址连续的存储单元从根结点出发,自上而下,从左至右的存储完全二叉树上的结点元素。

二叉树的顺序存储
在上图中可以看到,对于任意一棵二叉树,我们在进行顺序存储时都可以按照完全二叉树的形式进行存储。

这种存储方式的优点在于我们可以通过数组下标来反映二叉树中各个结点之间的逻辑关系,如果存储的是一棵完全二叉树或者满二叉树,还能起到节省存储空间的效果。

但是该存储方式的缺点也比较明显,对于一棵普通的二叉树而言,更多的是如同上图用例中一样,树中每一层的结点数量都不是最多的结点数量,都会存在些许的空缺。

在这种情况下,如果我们要满足二叉树各个结点之间的逻辑关系,那只能在空缺的结点上增加不存在的空结点,反映到内存中则是将这些空结点的空间给空出来,这样不会起到节省空间的效果,反而还会浪费大量的空间。

下面我们通过一个实例来感受一下这个缺陷。

假设有一棵高度为h结点的数量为h的二叉树,那此时如果我们要通过顺序存储的方式来存储二叉树的话,我们则需要向内存空间申请 2 h − 1 2^h-1 2h1的空间数量,但是在这些空间中实际被使用的空间也仅有h个,其余的空间都是被浪费掉的。如下所示:
二叉树的顺序存储2

h = 10 h=10 h=10 时,此时我们需要申请1023个内存空间,而实际使用的空间只有10个,此时多余的1013个空间都是被浪费掉的。

如果树中结点存储的数据其类型为long long型,在64位的机器上,该数据类型需要8个字节的空间,在这种情况下我们则需要浪费8104个字节的空间,也就是8KB左右的内存空间,而实际使用的空间只有80个字节的空间,也就是不到0.1KB的空间。

那么我要存储这不到0.1KB大小的数据,我需要额外的浪费8KB的空间,这显然是不合适的。当树的高度增加到100/1000/10000……可想而知,此时浪费的空间相比于实际使用的空间来说是非常巨大的,

因此,二叉树的顺序存储结构更适合对满二叉树和完全二叉树这种空间利用率更高的特殊二叉树。

三、链式存储结构

对于一般的二叉树而言,顺序存储的空间利用率低下,因此二叉树一般采用的都是链式存储的形式,通过链表的结点来存储二叉树中的每个结点。

在二叉树中,结点的结构通常包括3个部分:存储数据的数据域data、指向左子树的左指针域lchild以及指向右子树的右指针域rchild

结点结构
在二叉树的链式存储中,数据域的数量和指针域的数量并没有明确的规定,因此可以存在多个数据域和指针域。

上图所示的只包含左指针域和右指针域的结点所组成的链表我们将其称为二叉链表。二叉链表在内存中存储时,每个结点都可以通过其左右指针域找到其对应的左右子树:

二叉链表
在二叉链表中,当一个结点的指针域为空指针时,表示该结点没有对应的左右子树,当指针域都为空时,则表示该结点为叶子结点。

但是因为二叉链表只能够找到结点的左右子树,因此如果我们需要遍历一棵二叉树的全部结点,我们只能传入该二叉树的根结点。

当我们需要找到一个结点的父结点时,对于二叉链表来说,就比较为难了。为了即能够找到一个结点的左右子树,还能找到该结点的父结点,此时我们便可在结点中增加一个指向父结点的指针parent

三叉链表

像这种同时拥有指向左右子树的左右指针和指向父结点的父指针的结点组成的链表我们将其称为三叉链表。

对于一棵二叉树而言,除了根结点没有父结点外,其余的结点都有且仅有唯一的一个父结点,因此,在三叉链表中,从任意一个结点开始,都能够找到二叉树中的所有结点:

三叉链表
对于二叉链表与三叉链表而言,这两种链表在基本操作的实现上就有一定的区别。例如当我想查找整个二叉树的全部结点时,如果使用的是二叉链表,此时我们只能从根结点出发才能够完成所有结点的查找工作;而使用三叉链表时,我们可以从任意结点出发,都能够完成所有结点的查找工作。

而使用不同的存储结构时,对应操作的实现也会有所不同。例如当我们使用顺序存储结构来实现查找二叉树中的全部结点时,我们可以根据结点的下标之间的关系来完成整棵二叉树的查找工作;当我们使用链式存储结构来实现时,我们则需要根据结点的指针域来完成整棵二叉树的查找工作。

因此对于二叉树的具体操作的算法的实现,我们需要根据实际的应用场合来选择合适的存储结构。比如对满二叉树和完全二叉树进行操作时,我们选择顺序存储的方式会更加方便;对已知根结点的一般的二叉树,需要访问其左右子树时,我们只需要选择二叉链表;如需要频繁访问父结点时,选择三叉链表则更为合适。

结语

在今天的内容中,我们详细介绍了二叉树的两种存储结构——顺序存储和链式存储:

  • 当我们要存储一棵完全二叉树时,我们可以通过顺序存储的方式来存储完全二叉树中的各个结点,这样能够最大程度的节省内存空间;
  • 当我们要存储一棵普通的二叉树是,我们更多的是采用链式存储的方式来存储二叉树中的各个结点,以此来提高空间的利用率;

二叉树的顺序存储结构是依靠完全二叉树中各个结点的编号之间的关系得以实现各个数据之间的逻辑关系;而链式存储结构是直接通过结点的指针域来实现二叉树中各个结点的逻辑关系。

在链式存储中,我们主要介绍了两种链式存储的方式——二叉链表和三叉链表:

  • 二叉链表是通过左右指针域来找到结点所对应的左右子树,适合已知根结点,需要对其左右子树进行操作的场合;
  • 三叉链表是通过左右指针域来找到结点对应的左右子树,通过父指针域来找到结点对应的父结点,适合需要频繁访问父结点和不知道根结点但需要访问树中所有结点的场合;

对于二叉树的不同的存储结构,以及不同的实现方式,其使用的场所也会有所区别,因此我们需要根据实际的应用场合来选择合适的存储结构。

今天的内容到这里就全部结束了,在下一篇内容中,我们将介绍二叉树的基本操作以及C语言的实现,大家记得关注哦!!!如果大家喜欢博主的内容,可以点赞、收藏加评论支持一下博主,当然也可以分享给身边需要的朋友。最后感谢大家的支持,咱们下一篇再见!!!

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

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

相关文章

Android 调试桥_ADB命令

Android 调试桥 ADB全称 【Android Debug Bridge】 是Android SDK中的一个命令行工具&#xff0c;adb命令可以直接操作管理Android模拟器或真实的Android设备&#xff08;手机&#xff09; ADB的工作原理 启动一个 adb 客户端时&#xff0c;此客户端首先检查是否有已运行的 …

逐步掌握最佳Ai Agents框架-AutoGen 十 Web应用

AutoGen系列来到了第十篇&#xff0c;从入门AutoGen,到熟悉chat agent工作方式&#xff0c;再到深入把玩RAG文档AI助理应用。终于&#xff0c;我们要结合Streamlit来做智能Web应用了。 Streamlit Streamlit是一款Web开发框架&#xff0c;适用于python快速完成一些大模型、数学…

直播美颜工具解析:美颜SDK核心技术与性能优化方法

本篇文章&#xff0c;小编将深入解析直播美颜SDK的核心技术及其性能优化方法&#xff0c;以期为开发者提供有价值的参考。 一、美颜SDK核心技术 1.实时人脸检测与识别 美颜SDK的核心技术之一是实时人脸检测与识别。这项技术基于深度学习算法&#xff0c;能够快速、准确地识别…

实验9 静态路由配置

实验9 静态路由配置 一、 原理描述二、 实验目的三、 实验内容四、 实验配置五、 实验步骤 一、 原理描述 网络中的每个路由器都会维护一张路由表或转发表。路由表的表项记录着目的网络信息以及下一跳I 地址。路由表可以手动配置&#xff0c;也可以通过路由算法动态生成。静态…

kali配置静态ip

kali配置静态ip 因为一些环境需要&#xff0c;本地linux主机需要搭建一个桥接模式的网络&#xff0c;那么直接就在kali中配置了&#xff0c; 打开vim /etc/network/interfaces 这里就需要自己配置一下ip&#xff0c;网关&#xff0c;路由等内容 这里参考&#xff1a;参考链接 …

C++ STL初阶(2):string 的模拟实现

此文的背景是自己实现库中的string&#xff0c;由于string的模版实现较为困难&#xff0c;我们只实现最简单char版本。 1.命名空间分割 为了避免与库中的string冲突&#xff0c;我们使用一个自己的命名空间中来分离并实现所有内容&#xff0c;并且将所有的声明和定义相分离&…

Three.js-实现加载图片并旋转

1.实现效果 2. 实现步骤 2.1创建场景 const scene new THREE.Scene(); 2.2添加相机 说明&#xff1a; fov&#xff08;视场角&#xff09;&#xff1a;视场角决定了相机的视野范围&#xff0c;即相机可以看到的角度范围。较大的视场角表示更广阔的视野&#xff0c;但可能…

P3. 创建个人中心页面

P3. 创建个人中心页面 0 概述Tips1 个人中心页面1.1 创建 Bot 表及 pojo, mapper1.2 实现 Bot 增删改查的 API1.3 实现个人中心页面前端 0 概述 主要介绍了一下添加一个表(类)&#xff0c;及其CRUD的前端和后端的实现方式&#xff0c;介绍的是通用的方法。 后端的CRUD很好写&am…

【Java面试】十五、HashMap相关

文章目录 1、二叉树1.1 二叉搜索树1.2 红黑树 2、散列表2.1 哈希冲突2.2 哈希冲突 - 链表法 3、HashMap的实现原理4、HashMap源码4.1 属性部分4.2 构造函数部分 5、HashMap的put方法的流程6、HashMap的扩容机制7、HashMap的寻址算法8、为何HashMap底层的数组长度一定是2的次幂 …

导入地址表钩取技术解析

前置知识 导入表 在一个可执行文件需要用到其余DLL文件中的函数时&#xff0c;就需要用到导入表&#xff0c;用于记录需要引用的函数。例如我们编写的可执行文件需要用到CreateProcess函数&#xff0c;就需要用到kernel32.dll文件并且将其中的CreateProcess函数的信息导入到我…

数据库管理-第198期 升级Oracle ACE Pro,新赛季继续努力(20240605)

数据库管理198期 2024-06-05 数据库管理-第198期 升级ACE Pro&#xff0c;新赛季继续努力&#xff08;20240605&#xff09;1 惊喜2 变化3 Oracle ACE总结 数据库管理-第198期 升级ACE Pro&#xff0c;新赛季继续努力&#xff08;20240605&#xff09; 作者&#xff1a;胖头鱼的…

【PCB]射频电路pcb设计

学习改变命运&#xff0c;技能成就未来&#xff01;❤~~ 1射频信号的基础知识及工作原理介绍 射频的基础知识介绍 2射频板PCB的布局要求 3射频板布局要求 4屏蔽帐设计 5射频板的层叠阻抗设计 6射频板的PCB布线原则 7射频板的PCB布线要求 8射频板的设计实战

kubeedge v1.17.0部署教程

文章目录 前言一、安装k8s平台二、部署kubeedge1.部署MetalLB(可选)2.cloud3.edge4. 部署nginx到edge端 总结参考 前言 本文主要介绍kubeedge v1.17.0的安装过程 主要环境如下表 应用版本centos7.0k8s1.28.2kubeedge1.17.0docker24.0.8centos7.0 一、安装k8s平台 本文主要参…

2024年6月1日 (周六) 叶子游戏新闻

Embracer探讨单机游戏大作涨价超过70美元的可能性在Embracer集团等待公布新公司名称的同时&#xff0c;他们对游戏大作的价格上涨做出了评论。几年来&#xff0c;游戏大作的价格已经达到了70美元的门槛。Embracer集团的CEO Lars Wingefors在采访中表示&#xff0c;电子游戏行业…

MySQL—多表查询—内连接

一、引言 &#xff08;1&#xff09;内连接查询语法 内连接查询的是两张表的交集部分的数据。&#xff08;也就是绿色部分展示的数据&#xff09; &#xff08;2&#xff09;内连接有两种形式&#xff1a; 1、隐式内连接 语法结构&#xff1a; 2、显示内连接 语法结构&#xf…

AIGC绘画设计——midjourney有哪些好用的关键词?

midjourney有哪些高级关键词&#xff1f; 这一期继续分享一些高级的关键词&#xff0c; 我有一些案例也是从其他博主那学习来的&#xff0c; 但为了尽可能不出错&#xff0c;每个案例都是自己尝试了很多次后才拿出来的。 挑选了几个效果比较好&#xff0c;使用场景较高的类型…

lux和ffmpeg进行下载各大主流自媒体平台视频

1、lux下载&#xff0c;链接&#xff1a;https://pan.baidu.com/s/1WjGbouL3KFTU6LeqZmACpA?pwdagpp 提取码&#xff1a;agpp 2、ffmpeg下载&#xff0c;跟lux放在同一个目录&#xff1b; 3、为lux、ffmpeg设置环境变量&#xff1b; 4、WINR&#xff0c;打开运行&#xff0…

手眼标定学习笔记

目录 标定代码&#xff1a; 手眼标定原理学习 什么是手眼标定 手眼标定的目的 eye in hand eye to hand AXXB问题的求解 标定代码&#xff1a; GitHub - pumpkin-ws/HandEyeCalib 推荐博文&#xff1a; https://zhuanlan.zhihu.com/p/486592374 手眼标定原理学习 参…

nexus搭建npm前端项目的私服

一、为什么要搭建私库 节省外网带宽加速maven构建部署第三方构件&#xff08;特别是无法从公共仓库下载的构件&#xff09;提高稳定性&#xff08;内网部署&#xff0c;更少地依赖外网&#xff09;降低中央仓库的负荷 构件&#xff0c;好比我们的藏书&#xff0c;去书店或商城…

【数据库】SQL--DDL(初阶)

文章目录 DDL1. 数据库操作1.1. 表操作1.1.1 创建1.1.2. 查询 2. 数据类型及案例2.1 数值类型2.2 字符串类型2.3 日期时间类型2.4 案例练习 3. 表操作--修改3.1 添加字段3.2 修改字段3.3 修改表名 4. 表操作-删除4.1 删除字段4.2 删除表 5. DDL小结 更多数据库MySQL系统内容就在…