【二叉树魔法:链式结构与递归的纠缠】(中)

简介: 【二叉树魔法:链式结构与递归的纠缠】(中)

【二叉树魔法:链式结构与递归的纠缠】(上):https://developer.aliyun.com/article/1425242


4.二叉树的节点个数以及高度


// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);


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


       求二叉树节点的个数我们最容易想到的就是遍历二叉树,然后遇到一个不为NULL的节点就加,但是我们本章主要是使用递归的思想,所有都采用递归的思想去解题。

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
  int size = 0;
  if (root == NULL)
    return 0;
  else
    size++;
  BinaryTreeSize(root->left);
  BinaryTreeSize(root->right);
}


我们首先看看上面的写法有什么错误,很明显,上面犯了一个很严重的错误,返回局部变量的值,我们知道,函数内创建的局部变量在函数释放时候,其空间会被销毁,那么上面的size就会得到一个随机值。

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
  static int size = 0;//静态变量,生命周期边长
  if (root == NULL)
    return 0;
  else
    size++;
  BinaryTreeSize(root->left);
  BinaryTreeSize(root->right);
    return size;
}


再看看上面的代码,我们将size用static修饰,那么此时size就会存放在静态区,此时size生命周期就会变长,但是在函数内部我们有一个给size初始化为0的语句,这样会不会在每次函数调用的时候都会初始化为0呢?不会,局部的静态变量初始化只会被执行一次。我们调试发现,当再次进入函数时,给size初始化为0的语句直接被跳过了。


运行结果:


       我们可以看到结果求出来了,也确实是正确的,但是我们可以发现,静态变量的size生命周期是和程序的生命周期相同的,如果我们后面再次调用函数,size会从上一次的基础上加上去,比如我们再调用一次函数,结果是:


 所以我们上面的函数是一次性的,只能使用一次,不方便,不过也有方法解决,我们此时就不用静态变量了,我们将size设置为全局变量,然后在每次调用的时候,手动将size的值赋值为0,但是这样不够优雅,下面我们来介绍一下递归方法。

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


递归图


这样结果就出来啦!!!


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


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


递归图:


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


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


递归图


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


 我们首先拿到这个题目,就可以确定我们是从根节点开始查找,然后再左子树,右子树查找,很明显的前序遍历,因此我们可以按照前序遍历的思路查找该值。、

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


我们看看上面的代码有问题嘛?很明显画个递归图就可以观察到问题。


【二叉树魔法:链式结构与递归的纠缠】(下):https://developer.aliyun.com/article/1425248

相关文章
|
数据挖掘 API Go
《Go 简易速速上手小册》第7章:包管理与模块(2024 最新版)(下)
《Go 简易速速上手小册》第7章:包管理与模块(2024 最新版)
129 1
Echarts手机端无刷新实现图表自适应横屏和竖屏的解决方案
Echarts手机端无刷新实现图表自适应横屏和竖屏的解决方案
601 0
|
10月前
|
程序员
程序员的挑战与机遇:中国技术人才的现状
在中国,程序员作为技术行业的中坚力量,面临着一系列独特的挑战和机遇。这些挑战不仅影响着他们的职业发展,也关系到整个技术行业的进步。本文将探讨中国程序员面临的一些主要问题,并分析这些问题背后的原因,同时探讨可能的解决方案。
183 1
|
6月前
|
消息中间件 缓存 负载均衡
php怎么解决高并发的问题
在PHP中处理高并发问题需要多方面的优化,包括使用缓存技术、异步处理、数据库优化、负载均衡、选择合适的架构以及优化服务器配置。通过结合这些技术,可以显著提高PHP应用的并发处理能力,确保在高并发场景下依然能够提供稳定和高效的服务。
150 12
|
域名解析 网络协议 安全
阿里云CDN
本文介绍阿里云CDN产品中涉及的基本概念,便于您更准确地理解和使用CDN产品。
278 5
|
存储 弹性计算 大数据
阿里云ECS在大数据处理中展现高效存储与计算实力,提供多样化实例规格适应不同需求
【7月更文挑战第3天】阿里云ECS在大数据处理中展现高效存储与计算实力,提供多样化实例规格适应不同需求,如大数据型实例配备高吞吐硬盘。与OSS集成实现大规模存储,通过Auto Scaling动态调整资源,确保任务高效运行。案例显示,使用ECS能提升处理速度、降低成本,为企业数据驱动创新提供有力支持。
239 1
|
存储 缓存 安全
阿里云服务器通用型实例规格特点、适用场景、收费标准和活动价格参考
阿里云服务器通用型实例规格有哪些?最新价格是多少?阿里云服务器通用型实例规格有X86计算和ARM计算两种架构,每种架构都包含了不同类型的通用型实例,所以相同cpu和内存配置的通用型实例云服务器,收费价格标准也大不相同,下面小编为大家汇总一下哪些实例属于通用型实例规格,它们的最新收费价格标准又是怎样的,以供参考选择。
阿里云服务器通用型实例规格特点、适用场景、收费标准和活动价格参考
VsCode通过snippet generator快速生成自定义代码片段
VsCode通过snippet generator快速生成自定义代码片段
1115 0
VsCode通过snippet generator快速生成自定义代码片段
|
关系型数据库 MySQL Serverless
MYSQL数字函数:不可不知的数据处理利器
MYSQL数字函数是数据处理的得力助手,高效、准确且灵活。从基础数学运算到复杂数据转换,如ROUND、CEILING、FLOOR等,它们都能轻松胜任。ROUND函数实现数据四舍五入,而CEILING和FLOOR则分别进行向上和向下取整。这些函数不仅提升数据处理效率,还保障数据精确性和一致性。在数据分析、报表生成及业务逻辑处理中,MYSQL数字函数均扮演关键角色。对于数据处理开发者而言,熟练掌握这些函数是不可或缺的技能,它们将极大助力工作并提升职业竞争力。
311 6
|
Android开发 Kotlin
android开发,使用kotlin学习LiveData
android开发,使用kotlin学习LiveData
196 1