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

news2024/9/21 7:45:03

一.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://www.coloradmin.cn/o/1617203.html

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

相关文章

《从零开始的Java世界》10File类与IO流

《从零开始的Java世界》系列主要讲解Javase部分&#xff0c;从最简单的程序设计到面向对象编程&#xff0c;再到异常处理、常用API的使用&#xff0c;最后到注解、反射&#xff0c;涵盖Java基础所需的所有知识点。学习者应该从学会如何使用&#xff0c;到知道其实现原理全方位式…

【养生】个人参考:五脏运动

如有侵权可以下架&#xff0c;仅应用于个人查阅

BM25检索算法 python

1.简介 BM25&#xff08;Best Matching 25&#xff09;是一种经典的信息检索算法&#xff0c;是基于 TF-IDF算法的改进版本&#xff0c;旨在解决、TF-IDF算法的一些不足之处。其被广泛应用于信息检索领域的排名函数&#xff0c;用于估计文档D与用户查询Q之间的相关性。它是一种…

查看项目go代码cpu利用率

1.代码添加&#xff1a; "net/http"_ "net/http/pprof"第二步&#xff0c;在代码开始运行的地方加上go func() {log.Println(http.ListenAndServe(":6060", nil))}() 2.服务器上防火墙把6060打开 3.电脑安装&#xff1a;Download | Graphviz …

机器学习基础-PR\ROC\F1

1 1 、ROC曲线2 、PC曲线3、F14 、正负样本不均衡时怎么选择 1 、ROC曲线 就是TPR 与FPR 曲线 如图&#xff0c;就是根据阈值不同&#xff0c;我们看我们的二分类器的结果&#xff0c;根据结果算出TPR(真阳性)与FPR(假阳性)&#xff0c;最好的情况就是如图&#xff0c;我们的…

学习springcloud中Nacos笔记

一、springcloud版本对应 版本信息可以参考&#xff1a;版本说明 alibaba/spring-cloud-alibaba Wiki GitHub 这里说2022.x 分支对应springboot的版本信息&#xff1a; Spring Cloud Alibaba VersionSpring Cloud VersionSpring Boot Version 2022.0.0.0* Spring Cloud 202…

【C++】一篇文章带你深入了解list

目录 一、list的介绍二、 标准库中的list类2.1 list的常见接口说明2.1.1 list对象的常见构造2.1.1.1 [无参构造函数](https://legacy.cplusplus.com/reference/list/list/list/)2.1.1.2 [有参构造函数(构造并初始化n个val)](https://legacy.cplusplus.com/reference/list/list/…

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…

Matplotlib官网查阅资料

Matplotlib官网详细的地址&#xff1a; 英文文档&#xff1a;https://matplotlib.org/stable/contents.html中文文档&#xff1a;https://www.matplotlib.org.cn/ Matplotlib英文官网: 查找属性&#xff1a; 1.进入官网。 2.查找参数属性。 Matplotlib中文官网: 查找属性:…

SVN小乌龟汉化问题

1.首先确认中文语言包和SVN版本需要一致&#xff08;点击右键 选择最后一个选项即可查看&#xff09; 官网链接 点击这个官网链接可以下载对应版本的中文包 2.下载好之后直接无脑下一步安装即可 3.如果还是没有中文&#xff0c;找到这个文件夹&#xff0c;把里面的内容全部删…

【黑马头条】-day12项目部署和发布-jenkins

文章目录 1 持续集成2 软件开发模式2.1 瀑布模式2.2 敏捷开发2.2.1 迭代开发2.2.2 增量开发 3 Jenkins3.1 Jenkins安装3.1.1 导入镜像3.1.2 配置3.1.3 初始化设置 3.2 插件安装3.3 服务器环境准备3.3.1 Docker安装配置3.3.2 Git安装配置3.3.3 Maven安装配置 3.4 Jenkins工具配置…

接口测试和Mock学习路线(上)

一、接口测试和Mock学习路线-第一阶段&#xff1a; 掌握接口测试的知识体系与学习路线掌握面试常见知识点之 HTTP 协议掌握常用接口测试工具 Postman掌握常用抓包工具 Charles 与 Fiddler结合知名产品实现 mock 测试与接口测试实战练习 1.接口协议&#xff1a; 需要先了解 O…

截断堆积柱状图绘制教程

本教程原文链接&#xff1a;截断堆积柱状图绘制教程 欢迎大家转载&#xff01;&#xff01;&#xff01;&#xff01; 本期教程 写在前面 堆积柱状图是柱状图的常见类型之一&#xff0c;也是平时使用概率较高的图形之一。我们前期发布了很多个柱状图的绘制教程&#xff0c;若你…

Vue3、 Vue2 Diff算法比较

Vue2 Diff算法 源码位置:src/core/vdom/patch.ts 源码所在函数:updateChildren() 源码讲解: 有新旧两个节点数组:oldCh和newCh; 有下面几个变量: oldStartIdx 初始值=0 oldStartVnode 初始值=oldCh[0] oldEndIdx 初始值=oldCh.length - 1 oldEndVnode 初始值=oldCh[ol…

java多线程-悲观锁、乐观锁

简介 悲观锁&#xff1a;没有安全感&#xff0c;一上来就直接加锁&#xff0c;每次只能一个线程进入访问&#xff0c;访问完毕之后&#xff0c;再解锁。线程安全&#xff0c;但是性能差。乐观锁&#xff1a;很乐观&#xff0c;一开始不上锁&#xff0c;认为没有问题。等到要出现…

新的全息技术突破计算障碍

一种突破性的方法利用基于Lohmann透镜的衍射模型实时创建计算机生成全息图&#xff08;CGH&#xff09;&#xff0c;在保持3D可视化质量的同时&#xff0c;大大降低了计算负荷要求。 全息显示为制作逼真的三维图像提供了一条令人兴奋的途径&#xff0c;这种图像给人以连续深度…

【Linux系统编程】第七弹---权限管理操作(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、修改文件权限的做法(一) 2、有无权限的表现 总结 上一弹我们讲解了Linux权限概念相关的知识&#xff0c;但是我们只知道有…

[部分WP]DASCTF X GFCTF 2024 WEB

Web EasySignin 考点&#xff1a; 越权SSRF gopher协议去攻击mysql 通过注册任意用户修改admin密码 登入然后点击康好看图片 抓包 ?url 典型SSRF漏洞 尝试file读取/etc/passwd无果 尝试gopher协议去攻击mysql 利用工具gopherus 盲猜数据库用户为root 然后再次次url编码得到…

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

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

HarmonyOS ArkUI实战开发-NAPI 加载原理(下)

上一节笔者给大家讲解了 JS 引擎解释执行到 import 语句的加载流程&#xff0c;总结起来就是利用 dlopen() 方法的加载特性向 NativeModuleManager 内部的链接尾部添加一个 NativeModule&#xff0c;没有阅读过上节文章的小伙伴&#xff0c;笔者强烈建议阅读一下&#xff0c;本…