Day13.一刷数据结构算法(C语言版) 102二叉树的层序遍历;226翻转二叉树;101对称二叉树

一.102二叉树的层序遍历

        二叉树的层序遍历力扣题目

        1.思路分析

        这道题我没有什么好的思路,而且力扣给的函数形式看得有点懵,所以我找到一个相对好理解的题解,具体可以参考下方链接。 

        力扣题解

        说明:
        返回值:可以认为是一个动态分配的二维数组,行:树有几层就有几个int *指针,指向一个数组(存储了该层所有结点的值),列:每层结点的值
   int ** rslt = 【int *             | int *             | int *           | ...】       
                          ↓                     ↓                 ↓      ...         
              【int|int|...】       【int|int|...】    【int|int|...】    
 returnSize:用来返回二位数组的行树,即*returnSize = 有几层就赋值几
  returnColumnSizes:用来返回每层结点的个数,用一维数组来存储每层结点个数,这个数组要我们分配,调用者来free。

        不懂这个参数可以这样思考,如何要在函数内返回一个数组:
  1、通过返回值:
  int *p = f();
  int *f(void) {
     int *a = malloc(sizeof(int)*SIZE);
     return a;
  }
  2、通过参数:
  int *p = NULL;
  f(p);
  void f(int *a) {
     a = malloc(sizeof(int)*SIZE);
  }
  上面这样可以吗?当然不行,所以,要通过返回值返回一个在函数内分配的数组需要这样:
  int *p = NULL;
  f(&p);
  void f(int **a) {
     *a = malloc(sizeof(int)*SIZE);
  }

        2.代码详解

#define NODE_SIZE 10000
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes){int **rslt = NULL;int *columnSize = NULL;struct TreeNode *queue[NODE_SIZE] = {0};                    /* 做队列使用 */struct TreeNode *pNode = NULL;int front = 0, rear = 0, pre_rear;int i = 0, j = 0;                                           /* i用来索引行,即层数,j用来索引列,即每层的结点个数 */if (!root) {*returnSize = 0;return NULL;}queue[rear++] = root;                                       /* 先把root结点入队 */while (front < rear) {                                      /* 外层循环:用来处理队列,队列不为空就循环处理 */pre_rear = rear;                                        /* 备份上一层的队尾指针 */rslt = realloc(rslt, (i + 1)*sizeof(int *));            /* 外层循环实际就是层数,每次扩充1 */rslt[i] = calloc(pre_rear - front, sizeof(int));while(front < pre_rear) {                               /* 内层循环:遍历每一层结点,每次出队一个结点,同时并把该结点的孩子入队 */pNode = queue[front++];                             /* 出队 */rslt[i][j++] = pNode->val;                          /* 存储结点值 */if (pNode->left)                                    /* 当前结点左、右孩子存在则将他们入队 */queue[rear++] = pNode->left;if (pNode->right)queue[rear++] = pNode->right;}columnSize = realloc(columnSize, (i + 1)*sizeof(int));  /* columnSize数组用来存储每层结点个数 */columnSize[i++] = j;j = 0;}*returnSize = i;                                            /* 如上注释,这个参数用来“带回”层数 */*returnColumnSizes = columnSize;                            /* 这个参数用来“带回”每层的结点个数 */return rslt;                                                /* 返回值存储了遍历的结果,上面两个参数用来描述这个结果,以便调用者打印树的形态 */
}

 二.226反转二叉树

        题目建议:这道题目 一些做过的同学 理解的也不够深入,建议大家先看我的视频讲解,无论做过没做过,都会有很大收获。

        题目链接/文章讲解/视频讲解:代码随想录

        1.思路分析

        想要翻转它,其实就把每一个节点的左右孩子交换一下就可以了。

        关键在于遍历顺序,前中后序应该选哪一种遍历顺序? (一些同学这道题都过了,但是不知道自己用的是什么顺序)

        遍历的过程中去翻转每一个节点的左右孩子就可以达到整体翻转的效果。

        注意只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果

        这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次!建议拿纸画一画,就理解了

        那么层序遍历可以不可以呢?依然可以的!只要把每一个节点的左右孩子翻转一下的遍历方式都是可以的!

        我们下文以前序遍历为例,通过动画来看一下翻转的过程:

 

 

        我们来看一下递归三部曲:

        1)确定递归函数的参数和返回值

        参数就是要传入节点的指针,不需要其他参数了,通常此时定下来主要参数,如果在写递归的逻辑中发现还需要其他参数的时候,随时补充。

        返回值的话其实也不需要,但是题目中给出的要返回root节点的指针,可以直接使用题目定义好的函数,所以就函数的返回类型为TreeNode*

TreeNode* invertTree(TreeNode* root)

        2)确定终止条件 

        当前节点为空的时候,就返回。

if (root == NULL) return root;

         3)确定单层递归的逻辑

        因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。

swap(root->left, root->right);
invertTree(root->left);
invertTree(root->right);

         2.代码详解

struct TreeNode* invertTree(struct TreeNode* root){if(!root)return NULL;//交换结点的左右孩子(中)struct TreeNode* temp = root->right;root->right = root->left;root->left = temp;左invertTree(root->left);//右invertTree(root->right);return root;
}

三.101对称二叉树

        题目建议:先看视频讲解,会更容易一些。 

        题目链接/文章讲解/视频讲解:代码随想录

        1.思路分析

        首先想清楚,判断对称二叉树要比较的是哪两个节点,要比较的可不是左右节点!

对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。

        那么如何比较呢?

        比较的是两个子树的里侧和外侧的元素是否相等。如图所示:

        那么遍历的顺序应该是什么样的呢?

        本题遍历只能是“后序遍历”,因为我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。

        正是因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。

        但都可以理解算是后序遍历,尽管已经不是严格上在一个树上进行遍历的后序遍历了。

        其实后序也可以理解为是一种回溯,当然这是题外话,讲回溯的时候会重点讲的。

        说到这大家可能感觉我有点啰嗦,哪有这么多道理,上来就干就完事了。别急,我说的这些在下面的代码讲解中都有身影。

        那么我们先来看看递归法的代码应该怎么写。

        递归三部曲

        1)确定递归函数的参数和返回值

        因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。

        返回值自然是bool类型。

        代码如下:

bool compare(TreeNode* left, TreeNode* right)

        2)确定终止条件 

        要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚!否则后面比较数值的时候就会操作空指针了。

        节点为空的情况有:(注意我们比较的其实不是左孩子和右孩子,所以如下我称之为左节点右节点

  • 左节点为空,右节点不为空,不对称,return false
  • 左不为空,右为空,不对称 return false
  • 左右都为空,对称,返回true

        此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:

  • 左右都不为空,比较节点数值,不相同就return false

        此时左右节点不为空,且数值也不相同的情况我们也处理了。

        代码如下:

if (left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
else if (left->val != right->val) return false; // 注意这里我没有使用else

        注意上面最后一种情况,我没有使用else,而是else if, 因为我们把以上情况都排除之后,剩下的就是 左右节点都不为空,且数值相同的情况。

        3)确定单层递归的逻辑

此时才进入单层递归的逻辑,单层递归的逻辑就是处理 左右节点都不为空,且数值相同的情况。

  • 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
  • 比较内侧是否对称,传入左节点的右孩子,右节点的左孩子。
  • 如果左右都对称就返回true ,有一侧不对称就返回false 。

        代码如下:

bool outside = compare(left->left, right->right);   // 左子树:左、 右子树:右
bool inside = compare(left->right, right->left);    // 左子树:右、 右子树:左
bool isSame = outside && inside;                    // 左子树:中、 右子树:中(逻辑处理)
return isSame;

        如上代码中,我们可以看出使用的遍历方式,左子树左右中,右子树右左中,所以我把这个遍历顺序也称之为“后序遍历”(尽管不是严格的后序遍历)。 

        2.代码详解

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     struct TreeNode *left;*     struct TreeNode *right;* };*/
bool compare(struct TreeNode* left,struct TreeNode* right){if(left!=NULL && right==NULL) return false;else if(left==NULL && right!=NULL) return false;else if(left==NULL && right==NULL) return true;else if(left->val!=right->val) return false;bool out=compare(left->left,right->right);bool in=compare(left->right,right->left);bool compareLeaf=in && out;return compareLeaf;
}bool isSymmetric(struct TreeNode* root) {if(root==NULL) return true;return compare(root->left,root->right);
}

         如果你有问题或者有其他想法,欢迎评论区留言,大家可以一起探讨。 

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

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

相关文章

全国832个贫困县名单及精准扶贫脱贫(摘帽名单)数据(2016-2020.11)

01、数据简介 自党的十八大以来&#xff0c;我国脱贫攻坚战取得了举世瞩目的伟大胜利。经过全党全国各族人民的共同努力&#xff0c;现行标准下9899万农村贫困人口全部脱贫&#xff0c;832个贫困县全部摘帽&#xff0c;12.8万个贫困村全部出列&#xff0c;区域性整体贫困得到解…

BFS解决八数码问题-java

本文主要通过BFS广度优先搜索来解决八数码问题。 文章目录 前言 一、八数码 二、算法思路 1.思路模拟 2.实现思路 三、代码 1.代码如下&#xff1a; 2.读入数据 3.代码运行结果 总结 前言 本文主要通过BFS广度优先搜索来解决八数码问题。 提示&#xff1a;以下是本篇文章正文内…

7.2K star!一个完全免费,可以本地部署的 AI 搜索聚合器。新手可尝试

原文链接&#xff1a;7.2K star&#xff01;一个完全免费&#xff0c;可以本地部署的 AI 搜索聚合器。新手可尝试 ChatGPT 刚上线的时候我用的很少&#xff0c;还是习惯用 Google。主要还是因为不信任&#xff0c;怕它对我胡说八道。 慢慢的&#xff0c;也没有一个明确的时间…

工业4.0!智能工厂的智能物流系统应用

agv 智能物流系统通常指连接生产设备之间、车间之间以及车间与仓库之间的物流搬运系统。 为实现智能物流系统搭建&#xff0c;应该在尊重原有印刷生产工艺与合理生产布局基础上&#xff0c;通过应用新的生产智能化装备来实现协调车间的整体调度。 agv智能工厂 在现代化的物料搬…

java后端项目:视积分抽奖平台

一、项目背景: 本次抽奖系统实现是在视频中内置一个线上活动抽奖系统,奖品是在一个时间段区间内均匀发布,用户可以在这个时间段内参与抽奖。 二、项目架构 活动抽奖平台采用微服务架构来完成,在功能上实现拆分为用户、网关、以及抽奖微服务,其中用户、网关是后台项目通…

智能家居—ESP32开发环境搭建

相关文章 毕业设计——基于ESP32的智能家居系统(语音识别、APP控制) 智能家居—ESP32开发环境搭建 一、下载安装二、验证三、资料获取 一、下载安装 下载安装 vscode 安装插件 创建工程 二、验证 写一个简单的函数来验证一下功能 void setup() {// put your setup c…

常见UI组件(二)

一、文本输入 1.1 概述 TextInput为文本输入组件&#xff0c;用于接收用户输入的文本内容 1.2 参数 Entry Component struct Index {build() {Column({space : 50}) {TextInput({placeholder:请输入用户名}).width(70%)TextInput({text:当前内容}).width(70%)}.width(100%).…

光学雨量计:高精度测量降水量的理想解决方案

光学雨量计&#xff1a;高精度测量降水量的理想解决方案 河北稳控科技光学雨量计是一种高精度测量降水量的理想解决方案。它利用光学原理&#xff0c;通过光束的衰减来测量降雨强度和累积降水量。相比传统的雨量计&#xff0c;光学雨量计具有更高的精度和可靠性&#xff0c;成…

科研基础与工具(论文写作)

免责申明&#xff1a; 本文内容只是学习笔记&#xff0c;不代表个人观点&#xff0c;希望各位看官自行甄别 参考文献 科研基础与工具&#xff08;YouTube&#xff09; 学术写作句型 Academic Phrase bank 曼彻斯特大学维护的一个网站 写论文的时候&#xff0c;不不知道怎么…

IDEA开启自动导包,自动删包

找到file----------->Settings选项 找到Editor-------->General------------>Auto Import选项 勾选两个选项&#xff0c;在点击Apply,在点击ok 最后就ok了

入门指南:从零开始学习ReactJS

&#x1f482; 个人网站:【 摸鱼游戏】【神级代码资源网站】【工具大全】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

2024三掌柜赠书活动第二十四期:containerd原理剖析与实战

目录 前言 Containerd的架构 Containerd的工作流程 Containerd的实战演示 关于《containerd原理剖析与实战》 编辑推荐 内容简介 作者简介 图书目录 书中前言/序言 《containerd原理剖析与实战》全书速览 结束语 前言 作为开发者&#xff0c;对于编程语言并不陌生&…

Win10下VS2015无法添加任何文件,提示未能加载文件或程序集“Microsoft.VisualStudio.JSLS...

错误&#xff1a;未能加载文件或程序集“Microsoft.VisualStudio.JSLS, Version14.0.0.0, Cultureneutral, PublicKeyTokenb03f5f7f11d50a3a”或它的某一个依赖项。系统找不到指定的文件。 解决&#xff1a; 1. 管理员身份打开cmd 2. cd C:\Program Files (x86)\Microsoft Vis…

CommunityToolkit.Mvvm笔记---RelayCommand

RelayCommand 和 RelayCommand<T> 是 ICommand 实现&#xff0c;这些实现可向视图公开方法或委托。 这些类型充当在 viewmodel 和 UI 元素之间绑定命令的方法。 平台API&#xff1a;RelayCommand、RelayCommand<T>、IRelayCommand、IRelayCommand<T> 工作原理…

input的type=‘radio‘设置只读属性颜色为灰色,如何修改

目录 1.设置input和label的样式为不可点击。 2.设置input的readonly属性。 3.若想变回可修改&#xff0c;用js实现 4.如何自定义radio的颜色。 5.完整代码 input的单选框有时候需要实现只读&#xff0c;两个办法&#xff0c;一个disabled&#xff0c;一个是readonly. 但d…

【InternLM】Lagent智能体应用搭建

1. Lagent和AgentLego 1.1 Lagent Lagent 是一个开源的 LLM 智能体框架&#xff0c;允许使用者快速将一个大语言模型转换成智能体&#xff0c;并提供一些典型工具来激发大语言模型的潜能。Lagent 框架图如下&#xff1a; Lagent 包含三个主要模块&#xff1a;agents&#xf…

ubuntu18.04安装F4PGA教程

环境搭建教程&#xff1a; f4pga-arch-defs/xilinx/xc7 at main f4pga/f4pga-arch-defs GitHub git clone https://github.com/SymbiFlow/f4pga-arch-defs.git cd f4pga-arch-defs make env cd build 主要是make env&#xff0c;会下载很多东西&#xff0c;然后生成很多描…

38. 【Android教程】Handler 消息传递机制

跑在主线程&#xff08;即UI线程&#xff09;当中的&#xff0c;而且所有的 UI 刷新以及输入处理必须在主线程中执行。这样一旦任务多了就会阻塞 UI 线程导致画面卡顿&#xff0c;从而严重影响性能&#xff0c;所以正确的做法是将耗时的操作单独放在子线程中与 UI 线程隔离&…

本地代码配置多个远程仓库进行推送

Git配置多个远程仓库 问题解决办法新增远程地址推送 问题 目前一个项目正在一个仓库中存储&#xff0c;需要新增一个仓库&#xff0c;实现能同时推送到两个仓库中&#xff0c;比如一个项目同时维护在github和gitee上。 解决办法 新增远程地址 直接在本地项目根目录下输入: …