408数据结构-二叉树的概念、性质与存储结构 自学知识点整理

前置知识:树的基本概念与性质


二叉树的定义

二叉树是一种特殊的树形结构,其特点是每个结点至多只有两棵子树(即二叉树中不存在度大于 2 2 2的结点),并且二叉树是有序树,左右子树不能互换。
与树类似,二叉树也以递归形式定义。二叉树是 n n n n ≥ 0 n≥0 n0)个结点的有限集合。当 n = 0 n=0 n=0时,称为空二叉树
n ≠ 0 n≠0 n=0时,二叉树由根结点和两个互不相交的子树组成,左子树和右子树又分别是一棵二叉树。即使树中结点只有一棵子树,因为二叉树有序,也要区分是左子树还是右子树。
二叉树与度为 2 2 2的有序树的区别:

  • 度为 2 2 2的有序树至少有 3 3 3个结点,而二叉树可以为空。
  • 度为 2 2 2的有序树的孩子的左右次序是相对于另一个孩子而言的,若某一结点只有一个孩子结点,则无需区分其左右。而对二叉树上的结点来说,无论其孩子数是否为 2 2 2,均需确定其左右次序。即二叉树的结点次序不是相对于另一个结点而言的,而是确定的。

几种特殊的二叉树

Man! 满二叉树

一棵高度为 h h h,且有 2 h − 1 2^h-1 2h1个结点的二叉树被称为满二叉树。
因为对一个满二叉树来说,第 i i i层有 2 i − 1 2^{i-1} 2i1个结点,一共有 h h h层,则求和结果就是 2 h − 1 2^h-1 2h1
满二叉树的特点:

  1. 只有最后一层有叶子结点。
  2. 不存在度为 1 1 1的结点。
  3. 若层序从 1 1 1开始编号,则对第 i i i个结点,其左孩子必为第 2 i 2i 2i个结点,右孩子必为第 2 i + 1 2i+1 2i+1个结点。如果结点 i i i存在双亲结点,则其双亲必为第 ⌊ i / 2 ⌋ \left\lfloor i/2 \right\rfloor i/2个结点(即对 i / 2 i/2 i/2向下取整)。

(下图来自王道考研408数据结构课程视频 - 二叉树的定义和基本术语)
图片源自王道考研408数据结构课程视频

完全二叉树

一棵高度为 h h h、有 n n n个结点的二叉树,当且仅当其每个结点都与高度为 h h h的满二叉树中编号为 1 − n 1-n 1n的结点一一对应时,称为完全二叉树
完全二叉树的特点:

  1. 只有最后两层(层数最大的两层)可能有叶子结点。
  2. 最多只有一个度为 1 1 1的结点,且该结点只有左孩子而无右孩子。
  3. 层序从 1 1 1开始编号,则对第 i i i个结点,其左孩子必为第 2 i 2i 2i个结点,右孩子必为第 2 i + 1 2i+1 2i+1个结点。如果结点 i i i存在双亲结点,则其双亲必为第 ⌊ i / 2 ⌋ \left\lfloor i/2 \right\rfloor i/2个结点。(同满二叉树)
  4. 对结点 i i i,当 i ≤ ⌊ n / 2 ⌋ i≤ \left\lfloor n/2 \right\rfloor in/2时,该结点为分支结点;当 i > ⌊ n / 2 ⌋ i> \left\lfloor n/2 \right\rfloor in/2时,该结点为叶结点。
  5. n n n为奇数,则每个分支结点都有左孩子和右孩子;若 n n n为偶数,则编号最大的分支结点(编号为 n / 2 n/2 n/2)只有左孩子,没有右孩子,其余分支结点均有左、右孩子。

二叉排序树⭐

左子树上所有结点的关键字均小于根结点的关键字,右子树上所有结点的关键字均大于根结点的关键字,左右子树又各是一棵二叉排序树,这样的二叉树被称为二叉排序树

平衡二叉树⭐

树中任意一个结点的左子树和右子树的高度之差的绝对值不超过 1 1 1,这样的二叉树称为平衡二叉树
如果一棵二叉排序树是平衡的,那么它的搜索效率会高很多。

关于二叉排序树和平衡二叉树,后续章节会有详细介绍,现在暂时了解其概念即可。

正则二叉树

树中每个分支结点都有 2 2 2个孩子,即树中只有度为 0 0 0 2 2 2的结点。


二叉树的性质相关

常见考点1:非空二叉树上的叶结点数等于度为 2 2 2的结点数加 1 1 1,即 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1

假设树中结点总数为 n n n,度为 0 0 0的结点数为 n 0 n_0 n0,度为 1 1 1的结点数为 n 1 n_1 n1,度为 2 2 2的结点数为 n 2 n_2 n2。则有:
n = n 0 + n 1 + n 2 n=n_0+n_1+n_2 n=n0+n1+n2
n = n 1 + 2 n 2 + 1 n=n_1+2n_2+1 n=n1+2n2+1(树的结点数=总度数+1)
联立两式,得 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1
这一个考点常在选择题中涉及,需要牢记并灵活应用。

常见考点2:非空二叉树的第 i i i层至多有 2 i − 1 2^{i-1} 2i1个结点( i ≥ 1 i≥1 i1

由树的基本概念与性质可知, m m m叉树的第 i i i层至多有 m i − 1 m^{i-1} mi1个结点( i ≥ 1 i≥1 i1),令 m = 2 m=2 m=2即可。

常见考点3:高度为 h h h的二叉树至多有 2 h − 1 2^h-1 2h1个结点( h ≥ 1 h≥1 h1

由树的基本概念与性质可知,高度为 h h h m m m叉树至多有 m h − 1 m − 1 \frac{m^h-1}{m-1} m1mh1个结点( i ≥ 1 i≥1 i1),令 m = 2 m=2 m=2,得有 2 h − 1 2^h-1 2h1个(满二叉树)。

完全二叉树的性质相关

常见考点1:具有 n n n个结点( n > 0 n>0 n0)的完全二叉树的高度 h h h ⌈ log ⁡ 2 ( n + 1 ) ⌉ \left\lceil {{\log }_{2}}\left( n+1 \right) \right\rceil log2(n+1) ⌊ log ⁡ 2 n ⌋ + 1 \left\lfloor {{\log }_{2}}n \right\rfloor +1 log2n+1

由完全二叉树的已知性质,假设完全二叉树的高度为 h h h,则有

2 h − 1 − 1 < n ≤ 2 h − 1 {{2}^{h-1}}-1<n\le {{2}^{h}}-1 2h11<n2h1 2 h − 1 ≤ n < 2 h {{2}^{h-1}}\le n<{{2}^{h}} 2h1n<2h

取对数后可解得

h − 1 < log ⁡ 2 ( n + 1 ) ≤ h h-1<{{\log }_{2}}\left( n+1 \right)\le h h1<log2(n+1)h h − 1 ≤ log ⁡ 2 n < h h-1\le {{\log }_{2}}n<h h1log2n<h

h = ⌈ log ⁡ 2 ( n + 1 ) ⌉ h=\left\lceil {{\log }_{2}}\left( n+1 \right) \right\rceil h=log2(n+1) h = ⌊ log ⁡ 2 n ⌋ + 1 h=\left\lfloor {{\log }_{2}}n \right\rfloor +1 h=log2n+1

由此可知,第 i i i个结点所在层次为 ⌈ log ⁡ 2 ( i + 1 ) ⌉ \left\lceil {{\log }_{2}}\left( i+1 \right) \right\rceil log2(i+1) ⌊ log ⁡ 2 i ⌋ + 1 \left\lfloor {{\log }_{2}}i \right\rfloor +1 log2i+1

常见考点2:对于完全二叉树,可以由结点数 n n n推出度为 0 0 0 1 1 1 2 2 2的结点个数 n 0 n_0 n0 n 1 n_1 n1 n 2 n_2 n2

由之前的结论可知,完全二叉树最多只有一个度为 n n n的结点,即 n 1 = 0 n_1=0 n1=0 1 1 1
n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1,则 n 0 + n 2 = 2 n 2 + 1 n_0+n_2=2n_2+1 n0+n2=2n2+1必为奇数。
若完全二叉树有 2 k 2k 2k(偶数)个结点,则必有 n 1 = 1 n_1=1 n1=1 n 0 = k n_0=k n0=k n 2 = k − 1 n_2=k-1 n2=k1
若完全二叉树有 2 k − 1 2k-1 2k1(奇数)个结点,则必有 n 1 = 0 n_1=0 n1=0 n 0 = k n_0=k n0=k n 2 = k − 1 n_2=k-1 n2=k1


二叉树的存储结构

1.顺序存储结构

二叉树的顺序存储是指用一组连续的存储单元依次自上而下、自左而右存储完全二叉树上的结点元素,即将完全二叉树上编号为 i i i的结点元素存储在一维数组下标为 i − 1 i-1 i1的分量中。
依据二叉树的性质,完全二叉树和满二叉树采用顺序存储比较合适,树中结点的序号可以唯一地反映结点之间的逻辑关系。这样既能最大可能地节省空间,又能利用数组元素的下标值确定结点在二叉树中的位置,以及结点之间的关系。

#define MaxSize 100
typedef struct TreeNode {
	int value;//结点中的数据元素
	bool isEmpty;//结点是否为空
}TreeNode;
TreeNode t[MaxSize];//静态顺序存储二叉树
int n;//记录结点总数

void TreeInit() {//初始化
	for (int i = 0; i < MaxSize; ++i)
		t[i].isEmpty = true;//将每个结点状态设为空
	return;
}

用这种方式存储的完全二叉树,对第 i i i个结点,其左孩子为 2 i 2i 2i,右孩子为 2 i + 1 2i+1 2i+1,父节点为 ⌊ i / 2 ⌋ \left\lfloor i/2 \right\rfloor i/2,所在层次为 ⌈ log ⁡ 2 ( i + 1 ) ⌉ \left\lceil {{\log }_{2}}\left( i+1 \right) \right\rceil log2(i+1) ⌊ log ⁡ 2 i ⌋ + 1 \left\lfloor {{\log }_{2}}i \right\rfloor +1 log2i+1
若该完全二叉树共有 n n n个结点,则对第 i i i个结点,判断其是否有左右孩子,以及是否为分支/叶子结点,可用以下逻辑实现:

bool Have_LeftChild(int i) {//判断结点i是否有左孩子
	return (2 * i <= n && !t[2 * i].isEmpty) ? true : false;
}

bool Have_RightChild(int i) {//判断结点i是否有右孩子
	return (2 * i + 1 <= n && !t[2 * i + 1].isEmpty) ? true : false;
}

bool Is_Leaf(int i) {//判断结点i是否为叶子结点
	return i > (n / 2) ? true : false;
}

如果不是完全二叉树,依旧按照顺序存储的方式存储二叉树,则数组下标将不再能够表示各结点之间的逻辑关系。为解决这个问题,可以将二叉树中的结点编号与完全二叉树一一对应,从而进行顺序存储。但是这样又会产生新的问题:假如一棵二叉树中除叶结点外的所有结点都只有右孩子,那么,若这棵二叉树深度为 h h h,则它需要使用 2 h − 1 2^h-1 2h1大小的数组对所有结点进行存放,空间利用率非常非常低。因此,除了完全二叉树可以采用顺序存储结构,一般的二叉树通常采用的都是链式存储结构。

2.链式存储结构

由于顺序存储的空间利用率较低,因此二叉树一般都采用链式存储结构,用链表结点来存储二叉树中的每个结点。在二叉树中,结点结构通常包括若干数据域和若干指针域。二叉链表至少包含 3 3 3个域:数据域 d a t a data data,左指针域 l c h i l d lchild lchild,右指针域 r c h i l d rchild rchild。实际运用中,还可以增加数据域或指针域比如增加一个指向父节点的指针,变成三叉链表的存储结构。
二叉树的链式存储结构描述如下:

typedef struct Elemtype {//复合数据域
	int value;//只有一个int类型
}Elemtype;
typedef struct BiTNode {//二叉链表结点
	Elemtype data;//数据域
	struct BiTNode* lchild, * rchild;//左、右孩子指针
//	struct BiTNode* parent;//父节点指针(根据实际需要决定是否添加)
}BiTNode, * BiTree;

由二叉链表的性质, n n n个结点的二叉链表共有 n + 1 n+1 n+1个空指针域,这一部分可用于构造线索二叉树。
(计算方法:度为 2 2 2的结点有 0 0 0个空指针域,度为 1 1 1的结点有 1 1 1个空指针域,度为 0 0 0的结点有 2 2 2个空指针域。由此前的性质可知,当 n 1 = 1 n_1=1 n1=1时, n 0 = n / 2 n_0=n/2 n0=n/2,空指针域数量为 1 + 2 ∗ n / 2 = n + 1 1+2*n/2=n+1 1+2n/2=n+1;当 n 1 = 0 n_1=0 n1=0时, n 0 = ( n + 1 ) / 2 n_0=(n+1)/2 n0=(n+1)/2,空指针域数量为 0 + 2 ∗ ( n + 1 ) / 2 = n + 1 0+2*(n+1)/2=n+1 0+2(n+1)/2=n+1。故无论 n n n的值为奇数还是偶数, n n n个结点的二叉链表的空指针域都为 n + 1 n+1 n+1个)

根结点的初始化操作如下:

BiTree root = NULL;//定义一棵空树
void InitBiTree() {//初始化根结点
	root = (BiTree)malloc(sizeof(BiTNode));
	root->data = { 1 };
//	root->parent = NULL;
	root->lchild = NULL;
	root->rchild = NULL;
	return;
}

插入根结点的左孩子:可依照此逻辑完成对二叉树的构建。

void InsertRLChild() {//插入新节点(根结点的左孩子)
	BiTNode* p = (BiTNode*)malloc(sizeof(BiTNode));
	p->data = { 2 };
	p->lchild = NULL;
	p->rchild = NULL;
	root->lchild = p;
//	p->parent = root;
	return;
}

完整代码可以看我的Github:传送门

若要对二叉树进行遍历,只能从根结点开始,依次向下。在之后的章节里还会继续讨论这个问题。
408考研初试中,通常都是考察不带父指针的情况,即考察使用二叉链表存储二叉树。
若从 0 0 0开始对结点进行编号,则对应的操作逻辑都需要进行更改。
以上。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

fastdfs安装

fastdfs安装步骤 一 、原理 FastDFS是一个开源的轻量级分布式文件系统&#xff0c;由跟踪服务器&#xff08;tracker server&#xff09;、存储服务器&#xff08;storage server&#xff09;和客户端&#xff08;client&#xff09;三个部分组成&#xff0c;主要解决了海量数…

Flutter笔记:Widgets Easier组件库(10)快速处理承若型对话

Flutter笔记 使用Widgets Easier组件库快速处理承若型对话 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://…

光固化打印--问题记录

平面翘起 原因&#xff1a;角度平&#xff0c;缺支持 解决&#xff1a; 45度角度摆放底部平面起皮 原因&#xff1a;缺少支撑&#xff0c;原始结构支持无法支撑平面。 解决&#xff1a;增加支撑

【数学 排列组合】1643. 第 K 条最小指令

本文涉及知识点 数学 排列组合 LeetCode1643. 第 K 条最小指令 Bob 站在单元格 (0, 0) &#xff0c;想要前往目的地 destination &#xff1a;(row, column) 。他只能向 右 或向 下 走。你可以为 Bob 提供导航 指令 来帮助他到达目的地 destination 。 指令 用字符串表示&am…

Mybatis之Sqlsession、Connection和Transaction三者间的关系

前言 最近在看Mybatis的源码&#xff0c;搜到这篇文章Sqlsession、Connection和Transaction原理与三者间的关系&#xff0c;debug之后发现有不少疑惑&#xff0c;于是按照原文整理了一下&#xff0c;记录下debug中的一些困惑点。 对于我们开发来讲&#xff0c;不管跟任何关系…

2024五一数学建模C题完整论文讲解(含完整python代码及几十个特征表、处理表、结果表)

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2024五一数学建模C题煤矿深部开采冲击地压危险预测完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文。 C题论文…

【Docker学习】docker version查看版本信息

就像很多应用一样&#xff0c;docker也使用version来查看版本信息。但因为docker包含有不少独立组件&#xff0c;version的作用范围会更广一些。 用法1&#xff1a; docker --version 描述&#xff1a; 输出安装的Docker CLI 的版本号。关于Docker CLI&#xff0c;请访问。 实操…

数字电路-5路呼叫显示电路和8路抢答器电路

本内容涉及两个电路&#xff0c;分别为5路呼叫显示电路和8路抢答器电路&#xff0c;包含Multisim仿真原文件&#xff0c;为掌握FPGA做个铺垫。紫色文字是超链接&#xff0c;点击自动跳转至相关博文。持续更新&#xff0c;原创不易&#xff01; 目录&#xff1a; 一、5路呼叫显…

如何免费体验 gpt2-chatbot

如何免费体验 gpt2-chatbot 就在五一假期期间&#xff0c;一个神秘模型在没有任何官方文件的情况下突然发布。发布后不到 12 小时就立即引起人工智能爱好者和专家们的关注。这个名为“gpt2-chatbot”的神秘新模型凭借其令人印象深刻的能力轰动全球。有人猜测它可能是 OpenAI 的…

Python爬取豆瓣电影Top250数据

任务 爬取豆瓣电影top250中的影片名称、影片海报、年份、地区、类型、评分、评价人数、总体评价&#xff0c;并输出到douban_top250.xlsx文件中 环境 Python 3.8 requests bs4 openpyxl 源码 # 创建一个新的Excel工作簿 workbook openpyxl.Workbook() # 获取默认的工作表…

新版security demo(二)前端

写这篇博客&#xff0c;刚好换了台电脑&#xff0c;那就借着这个demo复习下VUE环境的搭建。 一、前端项目搭建 1、安装node 官网下载安装即可。 2、安装脚手架 npm install -g vue-cli 使用脚手架搭建一个demo前端项目 vue init webpack 项目名称 3、安装依赖 这里安装…

OpenCV(三)—— 车牌筛选

本篇文章要介绍如何对从候选车牌中选出最终进行字符识别的车牌。 无论是通过 Sobel 还是 HSV 计算出的候选车牌都可能不止一个&#xff0c;需要对它们进行评分&#xff0c;选出最终要进行识别的车牌。这个过程中会用到两个理论知识&#xff1a;支持向量机和 HOG 特征。 1、支…

vivado Aurora 8B/10B IP核(9)- CRC、 Aurora 8B/10B内核的时钟接口端口

CRC 模块提供 16 位或 32 位 CRC&#xff0c;用于用户数据。 Aurora 8B/10B 内核的时钟接口端口 从相邻收发器四边形的时钟Xilinx 实现工具可以根据需要对南北路由和引脚交换到收发器时钟输入进行必要的调整&#xff0c;以将时钟从一个四线到另一个。 重要信息&#xff1a;共…

25计算机考研院校数据分析 | 哈尔滨工业大学

哈尔滨工业大学&#xff08;Harbin Institute of Technology&#xff09;&#xff0c;简称哈工大&#xff0c; 校本部位于黑龙江省哈尔滨市&#xff0c;是由工业和信息化部直属的全国重点大学&#xff0c;位列国家“双一流”、“985工程”、“211工程”&#xff0c;九校联盟 、…

【Java EE】Mybatis之XML详解

文章目录 &#x1f38d;配置数据库连接和MyBatis&#x1f340;写持久层代码&#x1f338;添加mapper接口&#x1f338;添加UserInfoXMLMapper.xml&#x1f338;单元测试 &#x1f332;CRUD&#x1f338;增(Insert)&#x1f338;删(Delete)&#x1f338;改(Update)&#x1f338;…

【MIT6.S081】Lab6: Copy-on-Write Fork for xv6(详细解答版)

实验内容网址&#xff1a;https://xv6.dgs.zone/labs/requirements/lab6.html 本实验的代码分支&#xff1a;https://gitee.com/dragonlalala/xv6-labs-2020/tree// Implement copy-on write 关键点: 内存引用计数、usertrap()、页表 思路: Copy on write 是为了优化在fork()时…

Benewake(北醒) 短距 TF-Luna 8m

北醒TF-Luna激光雷达在测距方面具有以下特点: 高精度测距:北醒TF-Luna激光雷达采用激光束对目标进行扫描和测量,可以获取目标的高精度位置信息。其工作原理保证了测距的稳定性和准确性。 小视场角:该雷达具有较小的视场角(FOV),这意味着它可以更精确地锁定和测量特定区域…

Go协程的底层原理(图文详解)

为什么要有协程 什么是进程 操作系统“程序”的最小单位进程用来占用内存空间进程相当于厂房&#xff0c;占用工厂空间 什么是线程 进程如果比作厂房&#xff0c;线程就是厂房里面的生产线&#xff1a; 每个进程可以有多个线程线程使用系统分配给进程的内存&#xff0c;线…

深入理解网络原理1

文章目录 前言一、网络初识1.1 IP地址1.2 端口号1.3 协议1.4 五元组1.5 协议分层 二、TCP/IP五层协议三、封装和分用四、客户端vs服务端4.1 交互模式4.2 常见的客户端服务端模型4.3 TCP和UDP差别 前言 随着时代的发展&#xff0c;越来越需要计算机之间互相通信&#xff0c;共享…

网络安全审计

一、什么叫网络安全审计 网络安全审计是按照一定的安全策略&#xff0c;利用记录、系统活动和用户活动等信息&#xff0c;检查、审查和检验操作时间的环境及活动&#xff0c;从而发现系统漏洞、入侵行为或改善系统性能的过程&#xff0c;它是提高系统安全性的重要手段。 系统…