搞定二叉树

树的名词与概念

在这里插入图片描述

子树:树是一个有限集合,子树则是该集合的子集。就像套娃一样,一棵树下面还包含着其子树。比如,树T1 的子树为 树T2、T3、T4,树T2的子树为 T5、T6 。 上图中还有许多子树没有标记出来 。

结点(Node):一个结点包括一个数据元素和若干指向其子树分支。比如,在树T1 中,结点A 包括一个数据元素A 和 三个指向其子树的分支。上图中共有 17 个结点 。

根结点(Root):一颗树只有一个树根,这是常识。在数据结构中,“树根”即根节点。比如,结点A 是树 T1 的根结点; 结点C 是树T1 的子结点,是树 T3 的根结点。

度(Degree):一个结点拥有的子树数。比如,结点A 的度为 3,结点G 的度为 3,结点H 的度为 1。

叶子(Leaf)/ 终端结点:度为 0 的结点被称为叶子结点,很形象吧。比如,对于树 T1来说,结点F、I、K、L、M、N、O、P、Q 均为叶子节点。

分支结点 / 非终端结点:和叶子结点相对,即度不为 0 的结点。

内部结点:顾名思义,在树内部的结点,即不是根结点和叶子结点的结点。

双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点

孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点

兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点

堂兄弟节点:双亲在同一层的节点互为堂兄弟节点;如上图:E、G、H互为堂兄弟节点

节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先

子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙

层次(Level):从根结点开始,根为第一层,根的孩子为第二层,依次往下。比如,结点K 在树 T1 中的层次为 4。

深度(Depth)/ 高度:指树的最大层次。比如,树 T1 的高度为 4 。

有序树: 树中任意节点的子结点之间有顺序关系,这种树称为有序树 。

无序树 : 树中任意节点的子结点之间没有顺序关系,这种树称为无序树,也称为自由树 。

森林:由m(m≥0)棵互不相交的树构成一片森林。如果把一棵非空的树的根节点删除,则该树就变成了一片森林,森林中的树由原来根节点的各棵子树构成 。

什么是二叉树

满足以下两个条件的树称之为二叉树:

1、本质上为有序树;
2、每个结点的度不能超过2,即结点的度仅能为0,1,2。

二叉树地性质

1、二叉树的第i层上至多有2^(i-1) 个结点;
2、如果二叉树的深度为K,那么此二叉树最多有2^k - 1个结点,最少有h个结点;
3、对任意一棵二叉树,如果其叶子结点数,也就是度为0的节点数为n0,度为2的结点数为n2,则n0=n2+1。

性质 3 的计算方法为:对于一个二叉树来说,除了度为 0 的叶子结点和度为 2 的结点,剩下的就是度为 1 的结点(设节点数为 n1),那么总结点数 n=n0+n1+n2。
同时,对于每一个结点来说都是由其父结点分支表示的,假设树中分枝数为 B,那么总结点数 n=B+1。而分枝数是可以通过 n1和 n2表示的,即 B=n1+2*n2。所以,n 用另外一种方式表示为 n=n1+2*n2+1。
两种方式得到的 n 值组成一个方程组,就可以得出 n0=n2+1。

在这里插入图片描述
4、具有n个结点的满二叉树深度为log2^(n+1);
5、在非空二叉树中,第i层的结点总数不超过2^i - 1, i>=1;
6、具有n个结点的完全二叉树的深度为log2^n + 1 (表示向下取整);
7、 最多只有一个度为1的节点:n1=0或1,n0 = n2 + 1,n0 + n2 一定是奇数;
8、有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:

若I为结点编号则 如果I>1,则其父结点的编号为I/2;

如果2I<=N,则其左孩子(即左子树的根结点)的编号为2I;若2*I>N,则无左孩子;

如果2I+1<=N,则其右孩子的结点编号为2I+1;若2*I+1>N,则无右孩子。

二叉树类型

(1)完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。(如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。)
在这里插入图片描述

完全二叉树除了满足普通二叉树的性质外,还满足以下性质:

n个结点的完全二叉树的深度为⌊log2n⌋+1; (注:⌊ ⌋表示向下取整)
对于任意一个完全二叉树来说,如果将含有的结点按照层次从左到右依次标号,对于任意一个结点 i ,完全二叉树还有以下几个结论成立:
1). 当 i >1 时,父结点为结点 ⌊i/2⌋ 。(i=1 时,表示的是根结点,无父结点)

2). 如果 2i>n(总结点的个数) ,则结点 i 肯定没有左孩子(左叶子结点);否则其左孩子是结点 2i 。

3). 如果 2i+1>n ,则结点 i 肯定没有右孩子;否则右孩子是结点 2i+1 。

(2)满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。(如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树。)
在这里插入图片描述

满二叉树除了满足普通二叉树的性质,还具有以下性质:

1、满二叉树中第 i 层的节点数为 2^(i-1)个。
2、深度为 k 的满二叉树必有 2^k - 1 个节点 ,
叶子节点数为 2^(k-1) 。
3、满二叉树中不存在度为 1 的节点,每一个分支点中都两棵深度相同的子树,且叶子节点都在最底层。
4、具有 n 个节点的满二叉树的深度为 log2^(n+1)。

(3)平衡二叉树——平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。(平衡二叉树是一种二叉排序树,其中每个结点的左子树和右子树的高度差至多等于1。它是二叉排序树的一个进化体,它有几种实现方式:红黑树、AVL树)
在这里插入图片描述

平衡因子:平衡二叉树是在二叉查找树的基础上进行构建,为了维持平衡二叉树的平衡,那么就需要一种机制来判断平衡二叉树是否是平衡的。这种机制就叫做平衡因子。平衡二叉树上某个结点的左子树深度减去右子树深度的值,就称为此结点的平衡因子。
最小不平衡树:距离插入结点最近的,且平衡因子的绝对值大于1的结点为根的子树,称为最小不平衡树。

平衡二叉树特点:

1、平衡二叉树是一种二叉查找树
2、每个结点的左子树的高度减去右子树的高度的绝对值不超过1
3、空树和左右子树都是平衡二叉树
4、相比红黑树,平衡二叉树比较适用于没有删除的情况

二叉搜索树(又称: 二叉排序树、二叉查找树)

在这里插入图片描述

二叉搜索树:可以为空树,或者是具备如下性质:

A. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;

B. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;

C. 任意节点的左、右子树也分别为二叉搜索树;

还有一种特殊情况:
在这里插入图片描述

这种情况下,二叉搜索树已经变更为链表,搜索一个元素的时间复杂度从O( log2^n )退化为O(n), 出现这种情况的原因是二叉搜索树没有自平衡的机制,所以就有了平衡二叉树。

什么是左旋?

左旋:指将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点
在这里插入图片描述

什么是右旋?

右旋:指将根节点的左侧往右拉,原先的左子节点变成新的父节点,并把多余的右子节点出让,给已经降级的根节点当左子节点
在这里插入图片描述

失衡 :当我们在一个平衡二叉树上插入一个结点时,有可能会导致失衡,即出现平衡因子绝对值大于 1 的结点,如下图,当插入结点后,其中key为53的结点失去了平衡,我们称该结点为失衡结点,我们必须重新调整树的结构,使之恢复平衡
在这里插入图片描述

不一定只有一个结点失去平衡,有可能插入一个结点会让多个结点失衡。这时候找最小的失衡子树的根节点作为失衡结点。
恢复平衡 : 那如何去恢复平衡,使得二叉搜索树依然成立为一棵平衡树?先来看平衡调整的四种类型:
在这里插入图片描述

举个例子:如第一个,当平衡二叉树为AB时,插入一个C结点,使得失衡了,失衡结点为A,此时因为C结点插入的位置为失衡结点的左孩子的左孩子,所以是LL型,以此类推。

为了恢复平衡,针对每一种都不一样,但目的都是调整为平衡的,且不能违背二叉搜索树的性质:如下图是每种失衡类型的解决方法,每个都不太一样,目的都是一样的,把key的值为中等的变为树的根,最小的放在左孩子,做大的放右孩子,通过这一目的,降低树的高度,也不用死记硬背。
在这里插入图片描述

AVL树

AVL树是根据它的发明者G.M.Adelson-Velsky和E.M.Landis命名的。它是最先发明的自平衡二叉查找树,也被称为高度平衡树。
在这里插入图片描述

AVL树本质上还是一棵二叉搜索树,它的特点是:
1、本身首先是一棵二叉搜索树。
2、带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)。

如果在AVL树中插入或删除节点后,使得高度之差大于1。此时,AVL树的平衡状态就被破坏,它就不再是一棵二叉树;为了让它重新维持在一个平衡状态,就需要对其进行旋转处理。AVL实现平衡的关键在于旋转操作。

红黑树

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。因而,红黑树是相对接近平衡的二叉树,并不是一个完美平衡二叉查找树
在这里插入图片描述

红黑树的性质
1、结点不是红色就是黑色
2、根节点是黑色的
3、每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)
4、从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点
5、每个叶子结点都是黑色的(叶结点即指树尾端NIL指针或NULL结点)

红黑树与AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O( log2^n),红黑树不追求绝对平衡,只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多

二叉树的存储结构

二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构。

顺序存储

顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储 。

对于完全二叉树的存储,仅需对其从根节点开始仅需编号,使用数组存储编号即可。取出式依据完全二叉树由左到右分布的性质恢复即可。

在这里插入图片描述

在这里插入图片描述
链式存储

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。

在这里插入图片描述

在这里插入图片描述

二叉树遍历: 线性化

#include <iostream>

typedef int ElemType;
typedef struct TreeNode
{
	//数据域
	ElemType data;
	//指针域,左孩子节点、有孩子节点
	TreeNode *left, *right;
	TreeNode(int val) : data(val), left(nullptr), right(nullptr) {
	}
}Node;

typedef struct LinkedNode {
	//数据域
	TreeNode *node;
	//指针域,指向下个节点
	LinkedNode *next;
	LinkedNode(TreeNode *n): node(n), next(nullptr){
	}
}LinkedQueue;

LinkedNode *head = nullptr;
LinkedNode *tail = nullptr;

LinkedNode* LinkedNodeInit() {
	TreeNode* node = new TreeNode(-1);
	LinkedNode* temp = new LinkedNode(node);
	head = temp;
	tail = head;
	return head;
}

void Push(TreeNode* node) {
	LinkedNode* next = new LinkedNode(node);
	tail->next = next;
	tail = next;
}

LinkedNode* Pull() {
	head = head->next;
	return head;
}
//层次遍历
void LeveOrder(TreeNode* node)
{
	LinkedNodeInit();
	Push(node);
	while (head != nullptr) {

		LinkedNode* linknode = Pull();
		if (!linknode)
			break;
		std::cout << linknode->node->data << "->";
		if(linknode->node->left)
			Push(linknode->node->left);
		if (linknode->node->right)
			Push(linknode->node->right);
	}

}
//先序遍历 根左右
void PreOrder(TreeNode* node) {
	//节点为空,什么都不做
	if (node != NULL) {
		//访问节点数据
		std::cout << node->data << "->";
		//递归地访问左子树
		PreOrder(node->left);
		//递归地访问右子树
		PreOrder(node->right);
	}
}
//中序遍历 左根右
void InOrder(TreeNode* node) {
	//节点为空,什么都不做
	if (node != NULL) {
		//递归地访问左子树
		InOrder(node->left);
		//访问节点数据
		std::cout << node->data << "->";
		//递归地访问右子树
		InOrder(node->right);
	}
}
//后序遍历 左右根
void PostOrder(TreeNode* node) {
	//节点为空,什么都不做
	if (node != NULL) {
		//递归地访问左子树
		PostOrder(node->left);
		//递归地访问右子树
		PostOrder(node->right);
		//访问节点数据
		std::cout << node->data << "->";
	}
}

int main()
{
	//二叉树遍历: 线性化
	TreeNode child10(10), child7(7), child13(13), child5(5), child9(9), child11(11), child18(18),
		child3(3), child6(6), child8(8), child12(12);

	child10.left = &child7;
	child10.right = &child13;
	child7.left = &child5;
	child7.right = &child9;
	child13.left = &child11;
	child13.right = &child18;
	child5.left = &child3;
	child5.right = &child6;
	child9.left = &child8;
	child11.right = &child12;

	PreOrder(&child10);//先序遍历: 10->7->5->3->6->9->8->13->11->12->18->
	std::cout << std::endl;
	InOrder(&child10);//中序遍历: 3->5->6->7->8->9->10->11->12->13->18->
	std::cout << std::endl;
	PostOrder(&child10);//后序遍历: 3->6->5->8->9->7->12->11->18->13->10->
	std::cout << std::endl;
	LeveOrder(&child10);//层次遍历: 10->7->13->5->9->11->18->3->6->8->12->
}

了解更详细

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

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

相关文章

Stable Diffusion:使用自己的数据集微调训练LoRA模型

Stable Diffusion&#xff1a;使用自己的数据集微调训练LoRA模型 前言前提条件相关介绍微调训练LoRA模型下载kohya_ss项目安装kohya_ss项目运行kohya_ss项目准备数据集生成关键词模型参数设置预训练模型设置文件夹设置训练参数设置 开始训练LoRA模型TensorBoard查看训练情况 测…

基于Googlenet深度学习网络的信号调制类型识别matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 深度学习与卷积神经网络 4.2 数据预处理 4.3 GoogLeNet结构 4.4 分类器 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ............…

聚焦电力行业CentOS迁移,麒麟信安受邀参加第六届电力信息通信新技术大会暨数字化发展论坛并发表主题演讲

为加快推进“双碳”目标下的新型能源体系和新型电力系统建设&#xff0c;深化新一代数字技术与电力业务的融合发展&#xff0c;促进电力行业关键技术自主创新、安全可控&#xff0c;助力电力企业数字化转型升级和高质量发展&#xff0c;2023年8月9-11日&#xff0c;第六届电力信…

攻防世界-warmup

原题解题思路 只有一张图片&#xff0c;就查看源代码&#xff0c;有一个source.php。 查看source.php&#xff0c;白名单中还有一个hint.php。 hint.php告诉我们flag的位置ffffllllaaaagggg 但是直接跳转是没用的&#xff0c;构造payload。 http://61.147.171.105:55725/sourc…

Dockerfile制作Web应用系统nginx镜像

目录 1.所需实现的具体内容 2.编写Dockerfile Dockerfile文件内容&#xff1a; 默认网页内容&#xff1a; 3.构建镜像 4.现在我们运行一个容器&#xff0c;查看我们的网页是否可访问 5.现在再将我们的镜像打包并上传到镜像仓库 1.所需实现的具体内容 基于centos基础镜像…

8.部署项目

项目地址&#xff1a;RuoYi-Cloud-Plus: 项目正式入驻 dromara 开源社区 迁移地址: https://gitee.com/dromara/RuoYi-Cloud-Plus 1.获取源码 需要有gitee账户 先把源码fork到自己的仓库中 需要多等待一段时间 勾选对应的环境 构建项目 2.sql导入 将sql导入到与sql文件名…

【uniapp】中 微信小程序实现echarts图表组件的封装

插件地址&#xff1a;echarts-for-uniapp - DCloud 插件市场 图例&#xff1a; 一、uniapp 安装 npm i uniapp-echarts --save 二、文件夹操作 将 node_modules 下的 uniapp-echarts 文件夹复制到 components 文件夹下 当前不操作此步骤的话&#xff0c;运行 -> 运行到小…

批量爬虫采集完成任务

批量爬虫采集是现代数据获取的重要手段&#xff0c;然而如何高效完成这项任务却是让许多程序员头疼的问题。本文将分享一些实际操作价值高的方法&#xff0c;帮助你提高批量爬虫采集的效率和专业度。 目标明确&#xff0c;任务合理划分&#xff1a; 在开始批量爬虫采集前&…

怎么查看小程序中的会员信息

商家通过查看会员信息&#xff0c;可以更好地了解用户&#xff0c;并为他们提供更个性化的服务和推荐。接下来&#xff0c;就将介绍如何查看会员信息。 商家在管理员后台->会员管理处&#xff0c;可以查看到会员列表。支持搜索会员的卡号、手机号和等级。还支持批量删除会员…

Rancher-RKE-install 部署k8s集群

一、为什么用Rancher-RKE-install 1.CNCF认证的k8s安装程序。 2.有中文文档。 二、安装步骤 1.下载Rancher-Rke的二进制包-下面是项目的地址 GitHub - rancher/rke: Rancher Kubernetes Engine (RKE), an extremely simple, lightning fast Kubernetes distrib…

代码随想录打卡—day21—【二叉树】— 8.21

1 530. 二叉搜索树的最小绝对差 530. 二叉搜索树的最小绝对差 想法&#xff1a;先直接中序遍历&#xff08;升序的序列&#xff09;过程中相邻两个数的差值取min&#xff0c;自己写一次AC代码&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* …

关于视频监控平台EasyCVR视频汇聚平台建设“明厨亮灶”具体实施方案以及应用

一、方案背景 近几年来&#xff0c;餐饮行业的食品安全、食品卫生等新闻频频发生&#xff0c;比如某火锅店、某网红奶茶&#xff0c;食材以次充好、后厨卫生被爆堪忧&#xff0c;种种问题引起大众关注和热议。这些负面新闻不仅让餐饮门店的品牌口碑暴跌&#xff0c;附带的连锁…

爬虫工具的选择与使用:阐述Python爬虫优劣势

作为专业爬虫ip方案解决服务商&#xff0c;我们每天都面对着大量的数据采集任务需求。在众多的爬虫工具中&#xff0c;Python爬虫凭借其灵活性和功能强大而备受青睐。本文将为大家分享Python爬虫在市场上的优势与劣势&#xff0c;帮助你在爬虫业务中脱颖而出。 一、优势篇 灵活…

32.Netty源码之服务端如何处理客户端新建连接

highlight: arduino-light 服务端如何处理客户端新建连接 Netty 服务端完全启动后&#xff0c;就可以对外工作了。接下来 Netty 服务端是如何处理客户端新建连接的呢&#xff1f; 主要分为四步&#xff1a; md Boss NioEventLoop 线程轮询客户端新连接 OP_ACCEPT 事件&#xff…

分享图片 | 快速浏览网页资源,批量保存、一键分享图片

前言 小伙伴学习吉他&#xff0c;有时需要在互联网搜索曲谱资源&#xff0c;而多数曲谱均为图片&#xff0c;并且为多页&#xff0c;在电脑上显示练习很不方便&#xff0c;需要停下来点击鼠标进行翻页&#xff0c;影响练习的连贯性。 为了解决上述问题&#xff0c;通常把图片…

【数据分析入门】Jupyter Notebook

目录 一、保存/加载二、适用多种编程语言三、编写代码与文本3.1 编辑单元格3.2 插入单元格3.3 运行单元格3.4 查看单元格 四、Widgets五、帮助 Jupyter Notebook是基于网页的用于交互计算的应用程序。其可被应用于全过程计算&#xff1a;开发、文档编写、运行代码和展示结果。 …

宇宙原理:黑洞基础。

宇宙原理&#xff1a;黑洞基础TOC 黑洞的数理基础&#xff1a;一个由满数组成的数盘&#xff0c;经过自然演进&#xff0c;将会逐步稀疏化、最终会向纯数方案发展&#xff1b;纯数方案虽然只有{2}、无数&#xff08;虚拟&#xff09;、{0,1,2,3}&#xff08;虚拟&#xff09;、…

jenkins同一jar包部署到多台服务器

文章目录 安装插件配置ssh服务构建完成后执行 没有部署过可以跟这个下面的步骤先部署一遍&#xff0c;我这篇主要讲jenkins同一jar包部署到多台服务器 【Jenkins】部署Springboot项目https://blog.csdn.net/qq_39017153/article/details/131901613 安装插件 Publish Over SSH 这…

量子非凡去广告接口

量子非凡去广告接口&#xff0c;免费发布&#xff0c;请各位正常调用&#xff0c;别恶意攻击 >>>https://videos.centos.chat/weisuan.php/?url

深入浅出带你玩转栈与队列——【数据结构】

W...Y的主页 &#x1f60a; 代码仓库分享 &#x1f495; 目录 1.栈 1.1栈的概念及结构 1.2栈的结构特征图 ​编辑 1.3栈的实现 1.3.1栈的初始化 1.3.2进栈 1.3.3出栈 1.3.4销毁内存 1.3.5判断栈是否为空 1.3.5栈底元素的读取 1.3.6栈中大小 1.4栈实现所有接口 2…