【二叉树】——链式结构(快速掌握递归与刷题技巧)

简介: 【二叉树】——链式结构(快速掌握递归与刷题技巧)

前言

       前边我主要介绍了二叉树的顺序结构,链式结构也只是简单提及,今天我们来详细介绍一下二叉树的链式结构。


1. 二叉树的链式结构

       二叉树的顺序结构是通过顺序表来存储二叉树的数据,那么链式结构就是通过链表,连接二叉树的各个节点,进而来实现二叉树的树形结构。链式二叉树存储不需要像堆那要必须是完全二叉树,它可以是一颗普通二叉树。

  1.1链式二叉树的结构

       二叉树的链式结构是指使用节点之间的指针连接来表示二叉树的结构。在链式结构中,每个节点都包含一个数据元素和指向其左子节点和右子节点的指针。一个二叉树的节点通常由两个部分组成:数据域和指针域。

typedef struct BinaryTree
{
  int data;//数据域
  struct BinaryTree* left;//指针域
  struct BinaryTree* right;//指针域
}BTNode;

        通过这种链式结构,我们可以方便地遍历和操作二叉树。最常见的遍历方法就是使用递归遍历二叉树。前边我们也简单介绍了二叉树的前序、中序、后续遍历。也很简单,但是在实际中,并不会这么直白的让你递归遍历二叉树,都是遍历的变形。

2. 二叉树初阶训练

2.1 二叉树节点个数

  如何计算一个二叉树的节点个数呢?

 链式结构的树使用递归来遍历最简单,也是最常用的遍历方法。这样写吗?

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

        节点是NULL就返回0,不为空就size++。看似没有问题,但深入思考一下就会发现端倪,每次递归都会重新创建一个size然后++,每次的size都加到了一个size上吗?其实并没有,size出了函数作用域就会销毁,递归到叶子节点返回后,前边的size就会被销毁。

        只要解决size作用域问题是不是就可以解决了?增加size的生命周期有两种方法,一个是使用全局变量,另一个是使用static修饰。这样虽然可以计算出二叉树的节点个数,但这样也存在缺点,这个函数的使用就会变成一次性的,如果在一个程序中多次调用,数据就会累计(如第一次是5,第二次就是10……),也有解决的办法就是每次使用前将size置为0。但这都不是这个问题的最优解,最优解就是使用递归解决。

       递归的核心就是分治,将一个复杂的过程分解成一个一个的类似子问题。要计算一颗二叉树的节点个数就只需要计算左子树节点个数+右子树节点个数+1。左子树又可以分为左子树右子树,直到叶子节点,叶子节点的左右子树为NULL,所以遇到NULL就返回0;那我们就可以这样写:

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

如下图:

        虚线代表的递归返回,返回节点的个数。这里也仅仅是一个简单的递归,有了这个题目的思路,我们来进阶一下。

2.2 叶子节点个数

       计算叶子节点个数也是使用递归,对这个问题进行分治,计算一棵树的叶子节点个数,也就是左子树和右子树中叶子节点的个数,子树又可以再分为左子树、右子树。遇到叶子节点就停止。使用递归可以大幅的减少代码的复杂度。现在就只需考虑一下递归停止的条件。叶子节点的左子树与右子树都为空,所有当根的左右子树都为NULL时就可以判定为叶子节点。

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

 例如这棵树,有三个叶子节点:

        当前节点为NULL就不是叶子节点返回0,如果左右子树都为NULL,则该节点就是叶子节点,返回1,最后将左子树和右子树的叶子节点个数相加,最终返回值就是叶子节点的个数。

2.3 第k层节点个数

        在前两个的基础上我们再来一个变形,计算第k层节点个数。这道题目不像前两个那要,它需要有控制一下递归的深度。

int BinaryTreeLevelKSize(BTNode* root, int k)

       传入一个k,和根节点,通过k来控制递归的深度。这里我们默认根节点的高度是1。如果遇到NULL就返回0;

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);    
}

例如这棵树:

        假设我们要计算第3层节点个数。第一次调用从根开始,k此时等于3,然后开始向下递归第二次调用,传参是k-1,到第二层时k=2,到第三层时,k=1。这里我们需要注意一下两个判断返回的顺序,要先判断当前节点是否为NULL,不为NULL才开始判断k是否为1。


总结

        本篇文章主要简单介绍了一下二叉树的链式结构,以及链式结构遍历的特点,通过一些简单的练习帮助大家更快上手二叉树的链式递归。理解并使用好递归的分治,对于后续的学习至关重要,希望这篇文章可以帮到您。最后,感谢阅读!

相关文章
|
分布式计算 API Linux
通义千问API:找出两篇文章的不同
本章我们将介绍如何利用大模型开发一个文档比对小工具,我们将用这个工具来给互联网上两篇内容相近但版本不同的文档找找茬,并且我们提供了一种批处理文档比对的方案
|
存储 中间件 开发工具
云计算的三个主要服务模型:IaaS、PaaS 和 SaaS
云计算的三个主要服务模型:IaaS、PaaS 和 SaaS
19576 0
|
存储 缓存 Java
阿里云云效产品使用合集之如何配置不同的分钟走不同的步骤
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
监控 前端开发 Linux
centos7系统安装部署zabbix5.0
【9月更文挑战第23天】在CentOS 7系统上部署Zabbix 5.0的步骤包括:安装MariaDB数据库及必要软件包,配置Zabbix仓库,设置数据库并导入Zabbix数据库架构,配置Zabbix服务器与前端参数,启动相关服务,并通过浏览器访问Web界面完成安装向导。
1043 0
|
算法
串ababaaababaa的next和串ababaabab的nextval
本文介绍了计算字符串的next数组和nextval数组的方法,通过分析两个具体的例子来展示如何计算这些数组,这些数组通常用于KMP算法中。
767 0
串ababaaababaa的next和串ababaabab的nextval
|
程序员 开发工具 Android开发
Android|使用阿里云推流 SDK 实现双路推流不同画面
本文记录了一种使用没有原生支持多路推流的阿里云推流 Android SDK,实现同时推送两路不同画面的流的方法。
252 7
|
消息中间件 存储 监控
解决方案 | 云消息队列RabbitMQ实践
在实际业务中,网站因消息堆积和高流量脉冲导致系统故障。为解决这些问题,云消息队列 RabbitMQ 版提供高性能的消息处理和海量消息堆积能力,确保系统在流量高峰时仍能稳定运行。迁移前需进行技术能力和成本效益评估,包括功能、性能、限制值及费用等方面。迁移步骤包括元数据迁移、创建用户、网络打通和数据迁移。
347 4
|
12月前
|
人工智能 自然语言处理 物联网
llama factory 从数据集起步 跑通 qwen系列开源生成式大模型 微调
`dataset_info.json` 文件用于管理 llama factory 中的所有数据集,支持 `alpaca` 和 `sharegpt` 格式。通过配置此文件,可以轻松添加自定义数据集。数据集的相关参数包括数据源地址、数据集格式、样本数量等,支持 Hugging Face 和 ModelScope 两个平台的数据集仓库。针对不同格式的数据集,提供了详细的配置示例,如 `alpaca` 格式的指令监督微调数据集、偏好数据集等,以及 `sharegpt` 格式的多模态数据集等。今天我们通过自定义数据集的方式来进行qwen2.5_14B_instruct模型进行微调
5459 7
|
存储 算法 C语言
数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)
数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)
635 1

热门文章

最新文章