当前位置: 首页 > news >正文

c语言-数据结构-如何用分冶法求得二叉树的节点数与高度?

二叉树

  • 前言
  • 一、二叉树的高度
  • 二、二叉树的节点总数
  • 三、二叉树的第k层节点的个数


前言

本文讲解如何求出二叉树的高度等问题


一、二叉树的高度

我们有两种方式,一种是遍历,第二种则是分冶法,因为遍历比较麻烦并且容易出错,遗漏节点,因此我们在这里讲解优解,也就是分冶法

顾名思义,分冶法,便是将一个问题转化为若干个小问题去解决,而我们遍历二叉树,二叉树分为根,左子树和右子树,那么我们便可以遍历根,将遍历左子树和右子树分别视为两个小问题
比如
在这里插入图片描述
以这张图为例,校长想要知道学校里的职务共分了多少级别,但他不能一个个的去找人调查,那么他就调用他所知道的两个院长,让院长分别去统计

院长呢,就调用自己手下的系主任,让系主任分别去调查

系主任就调用自己手下管理的辅导员,辅导员接着调用班长,班长调用舍长,就这么一层一层的调用下去,最后再一层层地返回,就可以得到最终结果

而最终分了多少级别,看的是级别最多的一方加本身这个级别,比如说信息学院中,院长设置了一个部长级别,部长下一个级别是系主任级别,而数理学院却没有设置部长级别,那么信息学院就比数理学院多了一个级别,并且级别数量要按照信息学院的来算,院长得到学院里除了自己之外的级别数量再加上自己本身,便得到了整个学院的级别总数

同样,计算二叉树的高度也是如此,我们将根节点的左子树高度和右子树高度进行比较,得到高度大的那一方,加上根节点本身的一层,便是二叉树的高度

即:二叉树的高度是左右子树高度大的 + 1
在这里插入图片描述
在这里插入图片描述

如图,lenum代表左子树遍历,rinum代表右子树遍历

我们从A节点开始,判断不为空,走下一步;
下一步执行TreeHeight(root->left),走到了B节点

判断B节点不为空,下一步走到了D节点

判断D节点不为空,下一步传递D节点的left指针走到了NULL,判断为空,返回到传D节点的函数,此时D的lenum为0;执行下一步,传递D节点的right指针,走到了NULL,判断为空,返回到传D节点的函数,此时D的rinum为0,进行rinum和lenum的大小比较,比较之后将大的那个数加1

注:加1的原因是它本身也要算是一个节点,比如一棵只有ABC三个节点的树,A的lenum和rinum都是1,比较之后采用rinum(左右子树高度相等时代码采取右子树的高度,也可修改为左子树的高度),而A节点本身也是独占一层,那么就需要rinum + 1,也就是算上本身

此时返回到传B节点的函数中,左子树D返回的值是1,即B的lenum为1

而右子树E同理,返回也是1,那么B的rinum也为1

比较后相等,则采用rinum + 1,此时传递B节点的函数返回2

也就是说A的lenum为2,接着进入A的右子树CFG,返回也为2,即rinum为2

之后进行判断,相等,采取rinum + 1 = 3,返回3,结束

最终得到该二叉树的高度为3

有的写法可能更加简洁,但是过程却不一定,比如:

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

这种写法代码看似是简便了,但是我们我们每个节点都会被传递调用TreeHeight函数很多次
比如,我们在比较TreeHeight(root->left) > TreeHeight(root->right)时,就要从A节点到NULL全部进行一次遍历,判断完成之后,我们要返回数值对吧,但是返回的是TreeHeight(root->left) + 1或者是 TreeHeight(root->right) + 1,我们不知道这两个函数的返回值是多少,因为我们刚刚只是用数值进行了比较,并没有定义一个变量开辟空间去存储它们的值,因此返回之后这个值就消失了,相当于没有任何一个院长、系主任记得这个数,校长也不记得,所以我们还要再次调用这个函数去求他具体的数值是多少
而图中处于最底层的舍长,先调用左NULL,再进入右NULL,返回,后面求值再调用左NULL,再调用右NULL,需要调用很多次,相当于舍长要一次次的统计宿舍人数,这就会使得过程十分麻烦,因此我们并不建议使用这种方法,而是采用每次都定义变量开辟空间去存储它的值

二、二叉树的节点总数

在这里插入图片描述
同理,求二叉树的节点总数 ,相当于校长想要知道学校的总人数

比如,当刚开学时,学校人数较少的时候,比如十几个人,校长如果一个一个统计的话会很方便,但是当学校正式开学学生全部到校有几千人时,校长不可能拿着小本本挨个人统计,因为这会很麻烦,此时校长就可以调用手下的院长,让院长统计每个院的人数,然后相加再加自己本身就得到学校的总人数了

而每个院长就会调用自己手下的系主任,让系主任去统计每个系有多少人,依次相加再加本身,就得到自己院的人数了

因此,统计二叉树节点总数时,我们要采用分冶法去解决
在这里插入图片描述
如图,我们同样采用分冶法,结果就是左子树所有节点+右子树所有节点+本身(1)
在这里插入图片描述

我们采用左子树和右子树相加加本身的解法,恰好可以计算到所有节点,比如我们通过计算演示得到D节点的TreeSize(root->left) 和TreeSize(root->right)均为0,返回0 + 0 + 1(1为D节点本身),此时回到传递B节点的函数中,此时B节点的TreeSize(root->left)结束,并且值为1,进入TreeSize(root->right),计算出也是1,那么TreeSize(root->left) + TreeSize(root->right)为2,最后加本身,即加1,得到3

验证BDE刚好为三个节点,后面过程同上

三、二叉树的第k层节点的个数

在这里插入图片描述

如图,我们想要求二叉树中第k层节点的个数,依旧可以从左右子树方面入手,因为某一层的节点个数便是由左子树节点数加右子树节点数得到

如图,我们将A节点定义为第一层,将DEFG定义为第k层,那么当我们针对A节点的左子树BDE时

此时,B节点为根节点,我们可以将B视为第一层,那么DEFG便是第k-1层

由此,我们可以得到:二叉树的第k层节点个数便是左右子树的第k-1层节点个数之和

在这里插入图片描述
在这里插入图片描述
如图代码所示,当root指向NULL时,返回0,也就是0个节点

当k = 1时,代表我们到达了第k层,并且此时root并不指向NULL,因此返回1,代表此处有一个节点

注:k == 1的判断条件是在root == NULL的判断语句之后,因此无需担心野指针风险

为什么是k = 1的时候到达第k层呢?

我们根据完整的二叉树图片来看,A节点在第一层,DEFG在第K层,那么我们可以倒过来看,将A节点视为第k层,DEFG视为第一层,那么k到1与1到k都是相同的路程,因此k=1时便代表到达了第k层

最后我们一步步地返回,执行左右子树的TreeKSize函数,将其相加即可得到第k层的节点个数

http://www.dtcms.com/a/287325.html

相关文章:

  • CSS篇——第一章 六十五项关键技能(上篇)
  • Node.js特训专栏-实战进阶:17.会话管理与安全存储
  • Rust+ChatBoxAI:实战
  • 多模态交互视角下生成式人工智能在中小学探究式学习中的认知支架效能研究
  • SpringBoot项目部署至云服务器
  • Django接口自动化平台实现(三)
  • YOLOv11改进 | RFAConv重塑空间注意力助力性能提升
  • 2025第15届上海国际生物发酵展:聚焦合成生物与绿色制造,共启生物经济新时代
  • 数据集下载网站
  • 进阶向:基于Python的智能客服系统设计与实现
  • Spring之【AnnotatedBeanDefinitionReader】
  • Django母婴商城项目实践(十一)- 用户信息模块之用户登录注册
  • 【vue-5】Vue 3 中的 v-model:双向数据绑定的全面指南
  • 基于Python的口腔正畸健康教育聊天机器人开发与评估研究
  • XSS漏洞学习总结
  • 【Linux】基本指令详解(三) 指令本质、三个查找指令、打包压缩、重要热键、linux体系结构、命令行解释器
  • 数据结构 队列
  • 《计算机网络》实验报告二 IP协议分析
  • 在摄像机视图中想像在普通 3D 视口里那样随意移动
  • ROS2 通过相机确定物品坐标位置
  • 【Git】报错:git config --global http.sslBackend “openssl“
  • Java Map 常用方法大全
  • 鸿蒙蓝牙通信
  • 高压电工作业证考试核心考点:电气安全基础篇
  • 异世界历险之数据结构世界(二叉树-leetcode)
  • 开发框架安全ThinkPHPLaravelSpringBootStruts2SpringCloud复现
  • 中间件安全攻防全解:从Tomcat到Weblogic反序列化漏洞介绍
  • 【Oracle】ORACLE OMF说明
  • windows 如何安装 wsl ubuntu
  • PostgreSQL 语法详解