树和二叉树基础

news2024/9/21 18:50:31

引言:

树是一种非线性的结构,也是由一个一个的结点构成。

树的一些基本概念:

节点的度:一个节点含有的子树的个数称为该节点的度;如上图:A的度为6

叶节点或终端节点:度为0的节点称为叶节点。

非终端节点或分支节点:度不为0的节点;

双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点。

孩子节点或子节点:如B是A的子节点。

兄弟节点:具有相同父节点的节点互称为兄弟节点

树的度:一棵树中,最大的节点的度称为树的度

节点的层次:从根开始定义,根为第一层,根的子节点是第二层,以此类推。

树的高度或深度:树中节点的最大层次,如上图:树的高度是4.(注意从1开始计数,同时也意味着空树就是0

树的表示

左孩子右兄弟表示法:

二叉树概念及结构

概念:

  • 每个结点最多有两颗子树,即二叉树不存在度大于2 的节点。
  • 二叉树的子树有左右之分,其子树的次序不能颠倒。、

二叉树的定义

因为孩子最多有两个,所以直接定义左孩子,右孩子即可。

二叉树的前、中、后序

首先需要明确任何一个二叉树分为3个部分:

  1. 根节点
  2. 左子树
  3. 右子树

注意左子树和右子树都是一个整体,然后从这个整体中再细分根节点、左子树、右子树。

前序(先根):根 左子树 右子树

中序:左子树 根 右子树

后序:左子树 右子树 根

这个前中后的顺序是根据根的位置而决定的

下面是前、中、后序的原码(利用递归去求解)

void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%c ", root->val);
	PrevOrder(root->left);
	PrevOrder(root->right);
}

void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	InOrder(root->left);
	printf("%c ", root->val);
	InOrder(root->right);
}

void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%c ", root->val);
}

特殊的二叉树

  1. 满二叉树:一个二叉树,如果每一个层的结点树都达到最大值,就称为满二叉树
  2. 完全二叉树:就是在满二叉树的基础上,前h-1层都是满的,但是最后一层不满,但是最后一层从左往右都是连续的。

二叉树的性质

  1. 如果规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个结点。
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点个数(也就是满二叉树的个数)是2^h-1
  3. 对任何一棵二叉树,如果度为0的叶节点的个数为n0,度为2的分支结点的个数为n2,则有n0 = n2+1.
  4. 若规定根节点的层数为1,具有n个结点的二叉树的深度h = LogN。

根据二叉树的性质进行解题

例题1:

由二叉树的性质3得到叶节点的个数是度为2的分支结点个数+1,所以直接199+1 = 200即可。

例题2:

选择题快速法:

直接假设n = 2,接着进行带入计算,与每个选项进行比较得到正确答案。

常规解法:

设未知数,度为0的结点个数有X0个,度为1的结点个数有X1个,度为2的结点个数有X2个.

就会得到X0+X1+X2 = 2n.

又因为X0和X2的关系X2+1 = X0.

又因为是一个完全二叉树所以度为1结点的个数要么是1要么是0,所以分两种情况,发现当X1 = 1时计算结果是小数,不符合题意,所以X1 = 0得出答案。

例题3:

解答:

假设这棵树的高度是h,假设最后一层缺了X个

本题也是将选择题的答案带到题目中进行比较,然后得出正确答案。

如何求一棵二叉树中结点的个数?

解法一:

采用循环遍历的思想

遍历这棵树的每一个结点,如果不是空,就size++,否则不进行++。

注意运用这种方法时,因为可能需要计算多颗树的结点,所以每次传参时,需要传一个新的size地址,在主函数中直接打印输出size的值

原码:
void TreeSize(BTNode* root,int* psize)//直接传地址
{
	if (root == NULL)
		return;
	else
	{
		(*psize)++;
		TreeSize(root->left, psize);
		TreeSize(root->right, psize);
	}
}

解法二:

采用分治的思想。

何为分治的思想,就是将一个比较复杂的问题进行一层一层的分解,直到分解到简单的层次。将大问题分解为小问题。

例如校长想要统计整个学校的人数,校长将这个任务分配给院长,院长再分配给每个班的班主任,每个班主任再分配给每个宿舍的宿舍长。

本题思路也是如此,统计整棵树的结点个数,将这颗树分为左子树和右子树,左子树再分为小的左子树和小的右子树,层层递归,直到最后一层加1。

原码:

int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
	/*if (root == NULL)
		return 0;
	else
	{
		return TreeSize(root->left) + TreeSize(root->right) + 1;
	}*/
}

如何求二叉树叶子节点的个数?

按照上面分支的思想,咱们举一反三~

int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	if (root->left == NULL && root->right == NULL)
		return 1;
	else
		return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

TIP:

只需要给出中序+任何一个前序或者后序,就可以将一个完整的二叉树还原出来

原因:

前序和中序都是知道根节点是哪个,但是并不知道左子树和右子树。

如果有了中序后,并且已知根节点,那么在中序排列中,在根节点的左边就是左子树,在根节点的右边就是右子树,就可以轻松将树还原出来。

关于二叉树的一些经典例题

例题1:二叉树的前序遍历

144. 二叉树的前序遍历 - 力扣(LeetCode)

题目描述:

注意事项:

利用递归的思想去进行前序遍历,注意在递归时,计数器一般需要传址,防止局部变量出生命周期就自动销毁。

假设计数器用全局变量,是不行的。

因为函数接口会被多次调用,全局变量会一直累加

原码:

//提前计算好树的结点的个数,方便创建动态数组的个数
int TreeSize(struct TreeNode* root)
{
    return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

void _PrevOrder(struct TreeNode* root,int* arr,int* pcnt)
{
    //前序递归遍历,将遍历的结点存储到动态数组中
    if(root == NULL)
        return;
    arr[*pcnt] = root->val;
    (*pcnt)++;
    _PrevOrder(root->left,arr,pcnt);
    _PrevOrder(root->right,arr,pcnt);
}


int* preorderTraversal(struct TreeNode* root, int* returnSize){

    int size = TreeSize(root);
    int* arr = (int*)malloc(sizeof(int) * size);
    int cnt = 0;
    //注意传地址,递归调用一般需要传址操作
    _PrevOrder(root,arr,&cnt);
    *returnSize = cnt;
    return arr;
}

例题二:二叉树的最大深度

104. 二叉树的最大深度 - 力扣(LeetCode)

题目描述:

解题思路:

同样采用分治的思想,求二叉树的最大深度,就是求左子树和右子树的最大深度,接着继续分治,求左子树中的小左子树和小右子树的最大深度,直到不可分解进行+1即可

原码:

int maxDepth(struct TreeNode* root){
    if(root == NULL)
        return 0;
    int leftmax = maxDepth(root->left) + 1;
    int rightmax = maxDepth(root->right) + 1;
    return leftmax > rightmax ? leftmax : rightmax;
}

例题3:判断平衡二叉树

110. 平衡二叉树 - 力扣(LeetCode)

题目描述:

解题思路:

本题要求二叉树的每一个结点都要满足左右两个子树的高度差的绝对值不超过1,所以先判断头结点的左右子树是否满足,如果头结点都不满足,那么直接就返回false

如果头结点满足,则继续向下递归左右子树的结点是否满足。

原码:

int MaxDepth(struct TreeNode* root)
{
    if(root == NULL)
        return 0;
    int leftDepth = MaxDepth(root->left);
    int rightDepth = MaxDepth(root->right);
    return leftDepth > rightDepth ? leftDepth+1 : rightDepth+1;
}

bool isBalanced(struct TreeNode* root){
    if(root == NULL)
        return true;
    //先判断头结点,接着再判断子节点
    int leftDepth = MaxDepth(root->left);
    int rightDepth = MaxDepth(root->right);
    return  abs(leftDepth-rightDepth) < 2 && isBalanced(root->left) && isBalanced(root->right);
}

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

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

相关文章

聊天机器人将取代人工客服?电商界的超级“贵人”

聊天机器人在全球范围内取得了成功&#xff0c;目前有58%的 B2B公司和42%的 B2C公司使用聊天机器人&#xff0c;而且这个数字预计还会继续增长。原因有很多&#xff0c;聊天机器人能够模拟人类交互并每天 24小时提供客户服务。当客户有疑问时&#xff0c;不用等上几小时才能得到…

【RabbitMQ】RabbitMQ 服务无法启动。系统出错。发生系统错误 1067。进程意外终止。

问题描述 RabbitMQ 服务无法启动。 rabbitmq-service.bat startRabbitMQ 服务正在启动 . RabbitMQ 服务无法启动。系统出错。发生系统错误 1067。进程意外终止。原因分析 RabbitMQ和Erlang版本不匹配。 解决方案 查询并安装RabbitMQ版本对应Erlang版本 https://www.rabbitm…

[ROS]yolov8部署ROS

Yolov8是一种基于PyTorch深度学习框架的轻量级目标检测算法&#xff0c;具有高效、准确和快速的特点&#xff0c;因此在机器人领域得到了广泛的应用。而ROS&#xff08;Robot Operating System&#xff09;是一个用于机器人软件开发的框架&#xff0c;提供了各种工具和库&#…

高级DBA带你解决达梦国产数据库数据同步至clickhouse数据库通用方法(全中国唯一一份)关键技术讲解

步骤1、安装达梦8国产数据库 参考笔者之前写的博文&#xff0c;怎么安装国产达梦8数据库&#xff0c;按博文提前装好&#xff01; https://blog.csdn.net/nasen512/article/details/126872483 步骤2、安装好clickhouse数据库 参考笔者之前写过的博文&#xff0c;将clickho…

Hadoop HDFS 高阶优化方案

目录 一、短路本地读取&#xff1a;Short Circuit Local Reads 1.1 背景 ​1.2 老版本的设计实现 ​1.3 安全性改进版设计实现 1.4 短路本地读取配置 1.4.1 libhadoop.so 1.4.2 hdfs-site.xml 1.4.3 查看 Datanode 日志 二、HDFS Block 负载平衡器&#xff1a;Balan…

python通过docker打包执行

背景 正常情况下,python脚本执行需要安装有python环境,那python环境虽然也可以通过移植的方法来安装,那总归是比较麻烦的,下面通过docker打包的方式来执行python脚本 1、安装python镜像 准备两个文件即可,dockerfile、requirements.txt两个文件的内容分别如下 同目录下…

如何做好住宅区门禁监控,这回总算说全了

门禁监控在现代社会中已经变得愈发重要&#xff0c;特别是在住宅小区。随着城市化进程的加速和人口密度的增加&#xff0c;住宅小区的安全管理成为了一个至关重要的挑战。为了确保居民的安全和财产的保护&#xff0c;门禁监控系统逐渐成为了必备的设施之一。 客户案例 太原某小…

人大金仓V8数据库安装补充资料

之前写过一篇人大金仓数据库安装文档,自我感觉太过简练。这里补充一些资料。 命令行安装过程中,英文提示还比较简单。 安装默认第一项是完整安装,第二项是安装客户端软件,第三项是自定义安装。 这里选择了第一项。 File Path需要输入license文件的绝对路径且包括文件名。…

Jetpack Compose Accompanist最近的更新-2023年8月25日

Jetpack Compose Accompanist最近的更新-2023年8月25日 这篇文章更新了Jetpack Compose Accompanist库的情况&#xff0c;介绍了其目的和最新上传的功能&#xff0c;包括Pager、Flow Layout、Navigation Animation和Insets-UI。同时&#xff0c;提到了对一些库未来发展的讨论。…

光伏瓦屋顶

光伏瓦是由非晶硅材料制成的有光伏电池的屋面板&#xff0c;把光伏组件嵌入支撑结构&#xff0c;使太阳能板和建筑材料结为一体&#xff0c;直接应用于屋顶&#xff0c;和普通屋面瓦一样安装在屋面结构上。然后&#xff0c;光伏材料和组件将光转化为电能&#xff0c;通过吸收太…

5步搞定!!1Centos 7设置elasticsearch 7.12.1开机自启动

搞虚拟机玩&#xff0c;从网上看了很多es开机自启的方法&#xff0c;都试了&#xff0c;没有效果&#xff0c;最后尝试了shell脚本的方式&#xff0c;记录一下&#xff01; .sh文件内容&#xff1a; #!/bin/bash export JAVA_HOME/path/to/elasticsearch/jdk export JRE_HOME$…

Mybatis学习|基本的crud、数据库字段与对照类字段不一致问题

1.查询&#xff1a;根据id去查用户 在Dao层的UserMapper接口中增加根据id查用户的方法&#xff0c;定义方法名、传的参数以及返回值 在与UserMapper接口绑定的UserMapper.xml中配置该方法对应的sql语句 编写测试用例 2.增加&#xff1a;插入一个新用户 在Dao层的UserMapper接…

Spring源码分析(十)Bean实例化(下)

目录 1.1 循环依赖1.2 属性填充1.2.1 populateBean方法1.2.2 initializeBean方法执行Aware方法执行BeanPostProcessor后置处理器的前置处理方法执行初始化方法执行BeanPostProcessor后置处理器的后置处理方法&#xff1a;postProcessAfterInitialization()&#xff0c;允许对be…

低代码在未来会颠覆开发行业吗?

今天是正经男&#xff0c;我们严肃讨论一下一直以来争吵不休的取代问题。 低代码开发平台&#xff0c;低代码技术会取代开发人员么&#xff1f; 一、背景 低代码开发平台的普及&#xff0c;让很多公司对快速生成应用抱有很大期望。甚至有人认为&#xff0c;低代码开发平台未来会…

IntelliJ IDEA 2023.2.1 Android开发变化

IntelliJ IDEA 2023.2.1之前的版本&#xff0c;Empty Activity是指Empty View Activity&#xff0c;而现在Empty Activity是指Empty Compose Activity&#xff0c;另外多了一个Empty View Activity的选项 这表明官方推荐使用Compose这种声明式的编程方式来描述UI&#xff0c;命…

正中优配:炒股软件自动提示买卖点?

股票商场好像大海般改变多端&#xff0c;许多股民往往由于没有精确的生意点而错失良机&#xff0c;导致亏损惨重。在这种情况下&#xff0c;许多炒股爱好者就开始寻觅主动提示生意点的炒股软件&#xff0c;以便在股票商场中抢占先机。 可是&#xff0c;真的有这样奇特的炒股软…

如何给文件夹设置密码

文件夹怎么设置密码,如何给文件夹设置密码?有些重要的文件或比较隐私的文件存放在电脑上&#xff0c;这些文件我们只希望自己能看到并使用&#xff0c;不希望别人访问。那么&#xff0c;最好的办法就是去对这些文件进行加密。 才不怕别人看到自己的隐私&#xff0c;设置密码&a…

什么是RESTful API,Spring MVC如何支持RESTful架构

文章目录 &#x1f388;个人主页&#xff1a;程序员 小侯 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 ✨收录专栏&#xff1a;Java框架 ✨文章内容&#xff1a;Spring MVC支持RESTful架构 &#x1f91d;希望作者的文章能对你有所帮助&#xf…

问道管理:日换手率达20是好是坏?

关于股票商场的出资者而言&#xff0c;日换手率是一个非常重要的目标。日换手率是指股票当日买卖量与该股总股本之比。假如一只股票的日换手率过高&#xff0c;那么就意味着该股票的流动性较强&#xff0c;而假如日换手率过低&#xff0c;那么就意味着该股票的流动性较弱。 那…

认识ESP32(什么是RSP32)

一、认识ESP32 ESP32 是一款由乐鑫信息科技&#xff08;Espressif Systems&#xff09;开发的微控制器&#xff08;Microcontroller&#xff09;&#xff0c;它广泛用于物联网&#xff08;IoT&#xff09;和嵌入式系统应用。以下是一些 ESP32 的主要特点&#xff1a; 双核处理…