二叉树的基本操作(如何计算二叉树的结点个数,二叉树的高度)

news2024/12/27 0:12:04

在这里插入图片描述

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻推荐专栏1: 🍔🍟🌯C语言初阶
🐻推荐专栏2: 🍔🍟🌯C语言进阶
🔑个人信条: 🌵知行合一
🍉本篇简介:>:讲解二叉树中如何计算二叉树的结点个数,叶子结点的个数,二叉树的高度,第k层结点的个数,以及在二叉树中如何查找查找目标值.
金句分享:
✨每个人身上都有太阳,主要是如何让它发光. --苏格拉底✨

前言

上一篇文章传送门
我们讲解了如何根据前序遍历构建 二叉树 ,以及 二叉树 的三种遍历(前、中、后序遍历)方法.
本文主要讲解对 二叉树 的几个节基本操作.

目录

  • 前言
  • 一、计算二叉树的结点个数
    • 代码实现:
  • 二、计算二叉树叶子结点个数.
    • 代码实现
  • 三、计算二叉树的高度
    • 代码实现
  • 四、计算二叉树第k层结点的个数.
    • 代码实现
  • 五、查找二叉树中的目标值
    • 代码实现
  • 六、总代码
    • 测试区
    • 接口实现区
    • 声明区

一、计算二叉树的结点个数

对于一棵 二叉树 ,如何计算它又多少个结点?

打工人篇:
遍历 二叉树 ,一个个数结点个数
创建一个变量count进行记录,然后遍历 二叉树 进行计数吗?那count变量创建在哪里呢?
方法一:
如果创建在函数内部,那么在递归过程中都会创建这个变量.这样累加结果不会保留.

方法二:如果是全局变量,可以实现在每次递归过程中累加的效果,但是进行第二次计算时,全局变量需要清零重新计算,否则会继续累加.全局变量终究是不妥当安全的.

领导篇: (分治法)让下属去做事
我们可以将一棵 二叉树 想象为学校的组织结构,如果校长想要知道全校的人数,他会怎么办?
校长总不可能一个个去数吧.打工人才是那样滴,领导才不会.校长可以找院长,让院长汇报他们学院有多少人,院长班导,班导寝室长(打工人),最后网上层层汇报.
校长只需要关注院长,院长只需要关注班导,班导只需要关注寝室长就行了.

二叉树 的每个结点只需要知道其 左右子树 的结点个数就行.

在这里插入图片描述

二叉树 的结点个数= 左子树+ 右子树 +1(自己本身).
在这里插入图片描述

代码实现:

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)//遇到NULL返回0
	{
		return 0;
	}
	int left = BinaryTreeSize(root->left);//计算左子树的结点个数
	int right = BinaryTreeSize(root->right);//计算右子树的结点个数
	return left + right + 1;//左子树的结点个数+右子树的结点个数+自己本身
}

二、计算二叉树叶子结点个数.

提示: 二叉树 经常使用递归算法,不理解时可以画代码的递归展开图,一层层分析.更加方便理解

  叶子结点:度为0的节点称为叶节点

当一个结点的 左子树 右子树都是NULL时,该结点便是叶子结点.
在这里插入图片描述

代码实现

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->left == NULL && root->left == root->right)//判断是否是叶子结点
	{
		return 1;
	}
	int left = BinaryTreeLeafSize(root->left);//统计左子树中叶子结点的个数
	int right = BinaryTreeLeafSize(root->right);//统计右子树中叶子结点的个数
	
	return left + right;
}

三、计算二叉树的高度

  如果校长需要知道全校最高的那个人,他只需要让院长去统计他们学院最高的那个人的身高,然后从院长报上来的身高中选出较大者即可.

同样采用分治的方法,如果我们需要知道这颗树的高度,只需要计算它的左子树的高度,和右子树的高度,然后取较高的那个一棵,加上自己这一层的高度.

的高度=max( 左子树的高度, 右子树的高度)+1(本身这一层).

代码1:

int TreeHeight(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	//选出左右子树中的较大者
	return TreeHeight(root->left) > TreeHeight(root->right)
		? TreeHeight(root->left) + 1 : TreeHeight(root->right) + 1;
}

这个代码看起来没有问题,但是效率极低,如果现实生活中校长这样做事,最难受的就是寝室长(最强打工人了).

  就好比是这样的,寝室长统计了寝室最高的人名单交给班主任,但是班主任它没有记录,他只知道A寝室的人最高,所以A寝室的寝室长又要报上去一遍,班主任这次知道具体身高了,往上报给院长,院长只知道是A导员班上的人最高,但是也没有记录具体数值,就又让A导员计算一遍,可气的是,A导员自己报上去之后,又没记录,又要找A寝室长汇报,如果这棵树的高度比较高的话,那么寝室长被叫的次数会很可怕.
第二层要被呼叫 2次
第三层要被呼叫 4次
第四层要被呼叫 8次
第五层要被呼叫 16次
… …

在这里插入图片描述

正确写法,将计算过的高度保存下来.

代码实现

//二叉树的高度
int TreeHeight(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int left = TreeHeight(root->left);//记录左子树的高度
	int right = TreeHeight(root->right);//记录右子树的高度
	return left > right ? left + 1 : right + 1;
}

四、计算二叉树第k层结点的个数.

k 层的结点个数=第 k-1 层的 左子树结点个数+ 右子树结点个数.

在这里插入图片描述

代码实现

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)//表示就是要计算的这层的结点个数
	{
		return 1;
	}
	int left = BinaryTreeLevelKSize(root->left, k - 1);
	int right = BinaryTreeLevelKSize(root->right, k - 1);
	return left + right;
}

五、查找二叉树中的目标值

二叉树 中寻找目标值,最需要注意的是返回值问题.
先判断根节点,根节点找到课
再搜索 左子树,如果 左子树找到了,则返回该结点.
左子树没有找到,再搜索 右子树,如果 右子树找到了,返回该结点
最后,如果 左右子树都没有找到,则返回NULL.

在这里插入图片描述

代码实现

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
		//先判断根节点
	if (root->data == x)
		return root;

	//先搜索左子树
	BTNode* left = BinaryTreeFind(root->left, x);
	if (left)//如果左子树找到了就返回左子树找到的结点
		return left;

	//再搜索右子树
	BTNode* right = BinaryTreeFind(root->right, x);
	if (right) // 右子树找到
		return right;

	//没找到
	return NULL;
}

二叉树 的基本操作就讲到这里了,后续会分享几个 二叉树 的相关oj题,希望对大家有所帮助.

欢迎友友们私信与牛牛讨论问题.,只是牛牛的认知范围有限,目前只关注c语言,数据结构,C++等部分领域.

求波三连,如果文章有用的话,方便点一下赞和收藏吗?
💗💗💗

在这里插入图片描述

六、总代码

测试区

#include "tree.h"
int main()
{
	//BTDataType arr[50] = { "ABD##E##CF##G##" };
	BTDataType arr[50] = { "ABD##E##CF##GH###" };
	int i = 0;
	BTNode* root = BinaryTreeCreate(arr, &i);

	// 二叉树节点个数
	printf("二叉树结点的个数是:");
	printf("%d", BinaryTreeSize(root));
	printf("\n");

	// 二叉树叶子节点个数
	printf("二叉树叶子结点的个数是:");
	printf("%d", BinaryTreeLeafSize(root));
	printf("\n");


	//二叉树第k层节点个数
	printf("二叉树第3层节点个数是:");
	printf("%d", BinaryTreeLevelKSize(root, 3));
	printf("\n");

	//二叉树第k层节点个数
	printf("二叉树高度是:");
	printf("%d", TreeHeight(root));
	printf("\n");

	// 二叉树查找值为x的节点
	BTNode* ret = BinaryTreeFind(root, 'H');
	if (ret)
	{
		printf("找到了该结点:%c", ret->data);
	}
	else
	{
		printf("没有找到该结点.\n");
	}

	BinaryTreeDestory(root);

	return 0;
}


接口实现区


#include "tree.h"

//根据前序遍历构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)//pi用于遍历这个数组
{
	//递归的结束条件是,当left和right都是NULL时
		if (a[*pi] == '#')//遇到NULL
	{
		(*pi)++;
		return NULL;
	}
	//如果不是NULL
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));//创建树结点
	root->data = a[(*pi)++];
	root->left = BinaryTreeCreate(a, pi);
	root->right = BinaryTreeCreate(a, pi);
	return root;
}



//二叉树的销毁
void BinaryTreeDestory(BTNode* root)
{
	if (root == NULL)//如果走到NULL则直接返回
	{
		return;
	}
	BinaryTreeDestory(root->left);
	BinaryTreeDestory(root->right);
	free(root);//这条语句一定要放在前面两条语句的后面,不然无法递归往下走.
}


// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int left = BinaryTreeSize(root->left);
	int right = BinaryTreeSize(root->right);
	return left + right + 1;//左子树的结点个数+右子树的结点个数+自己本身
}


// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->left == NULL && root->left == root->right)
	{
		return 1;
	}
	int left = BinaryTreeLeafSize(root->left);
	int right = BinaryTreeLeafSize(root->right);
	return left + right;
}

//二叉树的高度
//int TreeHeight(BTNode* root)
//{
//	if (root == NULL)
//	{
//		return 0;
//	}
//	int left = TreeHeight(root->left);
//	int right = TreeHeight(root->right);
//	return left > right ? left + 1 : right + 1;
//}

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


// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	int left = BinaryTreeLevelKSize(root->left, k - 1);
	int right = BinaryTreeLevelKSize(root->right, k - 1);
	return left + right;
}


// 二叉树查找值为x的节点

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->data == x)
		return root;

	//先搜索左子树
	BTNode* left = BinaryTreeFind(root->left, x);
	if (left)//如果左子树找到了就返回左子树找到的结点
		return left;

	//再搜索右子树
	BTNode* right = BinaryTreeFind(root->right, x);
	if (right) // 右子树找到
		return right;

	//没找到
	return NULL;
}

声明区

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

typedef char BTDataType;


typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

//根据前序遍历构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi);

// 二叉树销毁
void BinaryTreeDestory(BTNode* root);

// 二叉树节点个数
int BinaryTreeSize(BTNode* root);

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);

//二叉树的高度
int TreeHeight(BTNode* root);


// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

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

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

相关文章

内网隧道代理技术(八)之Python 反弹Shell

Python 反弹Shell Python介绍 Python由荷兰数学和计算机科学研究学会的吉多范罗苏姆于1990年代初设计&#xff0c;作为一门叫做ABC语言的替代品。Python提供了高效的高级数据结构&#xff0c;还能简单有效地面向对象编程。Python语法和动态类型&#xff0c;以及解释型语言的本…

月薪2万,被新同事15秒气走。

今年&#xff0c;AIGC掀起了巨浪&#xff0c;身边不少人感到前所未有的焦虑&#xff1a; 朋友圈好友晒出的AI美图&#xff0c;仅需15秒&#xff0c;竟比我2周的设计更出色&#xff1b; 公司用AI写的文案&#xff0c;转化率提升了10%&#xff0c;可能要优化人员了; 职场危机提前…

Boost序列化全解析

程序开发中&#xff0c;序列化是经常需要用到的。像一些相对高级语言&#xff0c;比如JAVA, C#都已经很好的支持了序列化&#xff0c;那么C呢&#xff1f;当然一个比较好的选择就是用Boost&#xff0c;这个号称C准标准库的东西。 什么时候需要序列化呢&#xff1f;举个例子&am…

可视化的工时管理:让项目进度真实可见

在现代项目管理中&#xff0c;工时表软件作为一种强大而有效的工具&#xff0c;能够帮助团队更好地管理项目进度。无论是大小型项目&#xff0c;正确使用工时表软件都可以提高团队的效率和项目的可追踪性。本文将介绍一些关键步骤&#xff0c;以帮助企业利用工时表软件来管理项…

【计算机图形学】期末总结大全,建议收藏

文章目录 一、图形学及其研究内容二、图形的输入设备和显示设备三、图形的显示设备四、显示子系统五、图形软件标准五、图形软件包六、习题七、直线段扫描转换算法八、直线段扫描转换算法练习题九、扫描线填充算法十、实区域填充算法十一、反走样技术十二、图形裁剪基础概念十三…

开源社区必会知识点— —git提交pr

开源社区必会 1 fork仓库并提交之后给开源社区提交pr 1.1 fork开源仓库 ①登录github&#xff0c;找到开源仓库A&#xff0c;然后点击fork 这样&#xff0c;就会在你自己github账号下创建一个同名的仓库B&#xff08;仓库名可修改&#xff09; ②然后本地修改&#xff0c;提…

[RocketMQ] Consumer消费者启动主要流程源码 (六)

客户端常用的消费者类是DefaultMQPushConsumer, DefaultMQPushConsumer的构造器以及start方法的源码。 1.创建DefaultMQPushConsumer实例 最终都是调用下面四个参数的构造函数: /*** 创建DefaultMQPushConsumer实例** param namespace namespace地址* par…

调用聚合数据API实现手机号码归属地查询

调用聚合数据API实现手机号码归属地查询 1&#xff0e;作者介绍2&#xff0e;相关介绍2.1 什么是聚合数据&#xff1f;2.2 API介绍2.3 手机号码归属地 3&#xff0e;实验过程3.1如何调用聚合数据API3.2代码实现3.3实验结果3.4问题分析 1&#xff0e;作者介绍 吝红凯&#xff0…

Python+requests+unittest+excel搭建接口自动化测试框架

一、框架结构&#xff1a; 工程目录 代码&#xff1a;基于python2编写 二、Case文件设计 三、基础包 base 3.1 封装get/post请求&#xff08;runmethon.py&#xff09; import requests import json class RunMethod:def post_main(self,url,data,headerNone):res Noneif h…

【C++】一些关于visual stdio,vscode,Mingw的思考 |bug

文章目录 今天在做YOLOV8的C部署时遇到的一些问题&#xff1a; 在进行一系列的操作之后会生成解决方案文件sln: 当然按道理到这一步之后&#xff0c;应该使用make命令进行下一步操作&#xff08;但是我确实不会make命令&#xff0c;所以准备进sln来生成解决方案&#xff09;&…

缓存和数据库一致性问题,看这篇就够了

阅读本文大约需要 10 分钟。 如何保证缓存和数据库一致性&#xff0c;这是一个老生常谈的话题了。 但很多人对这个问题&#xff0c;依旧有很多疑惑&#xff1a; 到底是更新缓存还是删缓存&#xff1f; 到底选择先更新数据库&#xff0c;再删除缓存&#xff0c;还是先删除缓存…

消息队列详解

文章目录 1、什么是消息队列2、使用场景3、消息队列与传统设计的区别1、传统设计2、并行处理调优3、消息队列 4、三大优点1、异步2、削峰3、解耦 5、缺点1、增加了系统复杂性。2、事务问题。3、可用性 6、MQ常见问题1、消息堆积问题怎么解决2、重复消费问题怎么解决3、如果避免…

消息队列Message Queue 0基础学习

一、定义 消息队列&#xff1a;一般我们会简称它为MQ(Message Queue)。Message Query&#xff08;MQ&#xff09;&#xff0c;消息队列中间件&#xff0c;很多初学者认为&#xff0c;MQ通过消息的发送和接受来实现程序的异步和解耦&#xff0c;mq主要用于异步操作&#xff0c;…

高效精细的企业发票管理:探索优质方案助力您提升财务效率

随着企业逐渐规范化&#xff0c;财务工作流程暴露了不足&#xff0c;在企业员工报销管理工作中常遇到以下问题&#xff1a; 1. 报销发票种类繁多&#xff0c;管理麻烦费时&#xff1b; 2. 手动合计报销金额费时费力、并且易出错&#xff1b; 3. 报销流程繁杂&#xff0c;填写…

【软考网络管理员】2023年软考网管初级常见知识考点(5)-以太网技术

涉及知识点 CSMA/CD技术&#xff0c;以太网帧结构&#xff0c;冲突域和广播域&#xff0c;高速以太网&#xff0c;交换式以太网&#xff0c;软考网络管理员常考知识点&#xff0c;软考网络管理员网络安全&#xff0c;网络管理员考点汇总。 文章目录 涉及知识点前言一、CSMA/CD…

【CV】常见的损失函数及应用举例:交叉熵、对比、余弦、Dice、Focal Loss

目录 前言均方误差&#xff08;MSE&#xff09;交叉熵损失&#xff08;Cross-Entropy Loss&#xff09;对比损失&#xff08;Contrastive Loss&#xff09;余弦相似度损失&#xff08;Cosine Similarity Loss&#xff09;交叉熵损失加权的Dice损失&#xff08;Dice Loss&#x…

【接口自动化测试】如何进行流程封装和基于加密接口的测试用例设计?

接口测试仅仅掌握 Requests 或者其他一些功能强大的库的用法&#xff0c;是远远不够的&#xff0c;还需要具备能根据公司的业务流程以及需求去定制化一个接口自动化测试框架的能力。所以&#xff0c;接下来&#xff0c;我们主要介绍下接口测试用例分析以及通用的流程封装是如何…

何为SaaS?国内做的好的SaaS平台有哪些?

国内做得好的saas平台有哪些啊&#xff1f; 什么是SaaS平台&#xff1f; SaaS是Software as a Service的缩写&#xff0c;意为软件即服务。 它是指将软件应用程序部署在云计算服务器上&#xff0c;通过网络提供给用户的一种模式。这个模式下&#xff0c;用户无需花费大量的资…

LNMP架构搭建

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、LNMP概述1.LNMP的特点2.LNMP工作原理 二、安装Nginx 服务1.安装需要的依赖包2.创建运行用户3.编译安装4.优化路径5.添加 Nginx 系统服务 三、安装mysql服务1.安…

机房如何选购STS静态转换开关,采购配置并上架投入使用

环境: 1.机房交换机设备 2.STS静态转换开关 3.16安4平方电源插头 4.6平方输入连接线 5.大功率接线器(3进3出) 6.PDU(C14插头) 问题描述: 机房如何选购STS静态转换开关,采购配置并上架投入使用 目前痛点 机房有些设备单电源,无法接入UPS,停电了就无法正常工作,为…