链式二叉树OJ题思路分享

这篇具有很好参考价值的文章主要介绍了链式二叉树OJ题思路分享。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

⏩博主CSDN主页:杭电码农-NEO⏩

⏩专栏分类:刷题分享⏪

⏩代码仓库:NEO的学习日记⏩

🌹关注我🫵带你刷更多C语言和数据结构的题!
  🔝🔝


链式二叉树OJ题思路分享



1. 前言🚩

链式二叉树这一个板块的考题还是比较多的,这里我给大家分享几道很经典的OJ题,仅供参考! 分别是 1. 单值二叉树力扣965题----- 2. 检查两棵树是否相同力扣100题 ----- 3. 对称二叉树 力扣101题


2. 单值二叉树🚩

2.1 审题🏁

链式二叉树OJ题思路分享

这个题很简洁,让我们判断一个二叉树所有节点的值是否相同,这里的题我们都最好用递归的思想解决,因为非递归往往比较困难.我们先从易到难.我们可以想到的思路是:

  • 如果二叉树为空树,我们应该返回true

当前节点不为空时,我们就要用分治的思想,先判断当前节点的左孩子是不是NULL节点,如果不是空节点就将当前节点存储的值与左孩子节点存储的值进行比较右边也是如此

  • 判断左右子树是否为空,不为空的子树就判断当前节点与子树节点存储的值是否相同

这种分治思想可以理解为我们当前节点与孩子节点的值相同后又去比较孩子节点与孩子的孩子节点是否相同,如果遇见不相同的返回false,相同就一直往下走直到遇见NULL


2.2 代码实现🏁

我们可以根据前面的两个判断写出这样的代码:

bool isUnivalTree(struct TreeNode* root)
{
    if(root==NULL)//如果树为空或当前节点为空就返回true
    {
        return true;
    }
    if(root->left!=NULL&&root->val!=root->left->val)
    {
        return false;
    }
    if(root->right!=NULL&&root->val!=root->right->val)
    {
        return false;
    }
}

这里需要注意的是,当 root==NULL时有两种情况,一是我们拿到的树本身就是一个空树,我们返回true是没有问题的,二是我们往后递归下去的某个节点是空节点,走到空节点代表这条路线上所有节点的值都一样,返回true也没问题

然而当我们走完上面代码后,既没有返回true也没有返回false,走到这里就代表此节点即不为空,并且它和它孩子的值也是相同的,所以这里我们就去到它的左右子树再次重复上面的过程

bool isUnivalTree(struct TreeNode* root)
{
    if(root==NULL)
    {
        return true;
    }
    if(root->left!=NULL&&root->val!=root->left->val)
    {
        return false;
    }
    if(root->right!=NULL&&root->val!=root->right->val)
    {
        return false;
    }
    return isUnivalTree(root->left)&&isUnivalTree(root->right);//左右子树的值都相同才返回true

}

3. 检查两颗树是否相同🚩

3.1 审题🏁

链式二叉树OJ题思路分享

判断两颗树是否相同,它不仅仅是值相同,值对应的左右孩子的顺序也要相同,这里我们还是采用分治递归的思想,把大事化小,把小事化了,这里我们首先可以想到的是,当着两棵树都为空树时,它们是相同的返回true.然而这里还会出现一种情况,那就是一棵树为空,另外一颗树不为空,这时它们是不相同的,返回false.当走完上面两个条件后,说明此时这两个节点都不为空,我们就接着判断在这个节点这两棵树的值是否相同

我们可以根据上面的讨论得到这样的结论:

  • 当两个树的节点都为空时返回true
  • 当两个树中一个节点为空另一个节点为非空返回false
  • 当两棵树都不为空,判断它们的值是否相同

3.2 代码实现🏁

我们根据上面的讨论可以写出这样代码:

bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
    if(p==NULL&&q==NULL)
    {
        return true;
    }
    if(p==NULL||q==NULL)
    {
        return false;
    }
    if(p->val!=q->val)
    {
        return false;
    }
}

当代码走完上面的步骤后没有返回true也没有返回false,这时说明这两个节点不为空,并且它们的值相同,这是我们就应该接着递归这两个节点的左右子树,不断重复上面的过程直到遇见不相同或为空的节点

bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
    if(p==NULL&&q==NULL)
    {
        return true;
    }
    if(p==NULL||q==NULL)
    {
        return false;
    }
    if(p->val!=q->val)
    {
        return false;
    }
    bool left = isSameTree(p->left,q->left);
    bool right = isSameTree(p->right,q->right);
    if(!left||!right)//如果左子树和右子树其中一个的结果是false,那么就返回false
    {
        return false;
    }
    else
    return true;
}

这里需要注意的点是,我们递归时是将节点一的左子树和节点二的左子树放在一起递归,节点一的右子树和节点二的右子树放在一起递归.这里不能搞混淆了.并且左右子树中只要有一个false,那么就直接返回false,因为只有节点一和节点二不相同时才会返回返回false给left或right

如果左右子树都不为false,那么就代表此节点的左右子树与另外一棵树的对应节点的左右子树是相同的


4. 对称二叉树🚩

4.1 审题🏁

链式二叉树OJ题思路分享

这个题和判断相同的二叉树很相似,上一题是左边与左边做判断,这个题要左边和右边做判断,如果是对称的二叉树的话,那么当前节点的左子树要等于当前节点的右子树,然后左子树的左子树要等于右子树的右子树,左子树的右子树要对应右子树的左子树,很绕.但是仔细一下确实是这样.我们还是用分治的思想,第一步如果当前节点的左孩子和右孩子都为空,或者说这棵树只有一层,那么它是对称的,返回true.第二步如果当前节点的左孩子或者右孩子有一个为空,一个不为空,那么这棵树就不是对称的,返回false.当我们走完上面两步还没有如何返回值时,证明左孩子和右孩子都不为空,这时就要判断左右孩子的值是否相同.

根据上面的思路总结:

  • 左右孩子都为空,返回true
  • 左右孩子其中一个为空另一个不为空返回false
  • 当左右孩子都不为空时比较左右孩子对应的值是否相同

4.2 代码实现🏁

需要注意的是,这里的接口函数的参数只有一个,但是我们递归的时候想要递归左子树的左子树与右子树的右子树,我们就需要两个参数,所以我们不能在原有的接口函数上进行递归,这里我们应该自己写一个函数用来递归

bool isSymmetric(struct TreeNode* root)
{
    if(root==NULL)
    {
        return true;
    }
    struct TreeNode* left=root->left;
    struct TreeNode* right=root->right;
    return myis(left,right);
}

这里我们先把接口函数的功能给实现了,然后再来看我们的自定义函数:

bool myis(struct TreeNode* left,struct TreeNode* right)
 {
     if(left==NULL&&right==NULL)
     {
         return true;
     }
     if(left==NULL||right==NULL)
     {
         return false;
     }
     if(left->val!=right->val)
     {
         return false;
     }
}

将上面所有代码走完后,如果还是没有返回值的话,证明此时的左节点和右节点即不为空,并且它们的值相同,所以我们就接着往下递归,不断重复上面的过程

bool myis(struct TreeNode* left,struct TreeNode* right)
 {
     if(left==NULL&&right==NULL)
     {
         return true;
     }
     if(left==NULL||right==NULL)
     {
         return false;
     }
     if(left->val!=right->val)
     {
         return false;
     }
     
     return myis(left->left,right->right)&&myis(left->right,right->left);
 }

这里递归的对象是左子树的左子树和右子树的右子树是一队,而左子树的右子树和右子树的左子树是一队.并且要它们两个都返回true时,才是真正对称的,所以用&&符号连接.


5. 二叉树的前中后序遍历🚩

这里我们只需要把二叉树的前序遍历的题目给理解了,中后序自然就简单了.


5.1 审题🏁

链式二叉树OJ题思路分享

首先我们要先知道接口函数的参数int* returnSize.这里它实际上不是告诉我们二叉树有多少个节点的意思,而是要我们自己求出二叉树的节点个数,然后解引用returnSize修改returnSize的值,最后调用接口函数和returnsize的值判断我们的代码正不正确.所以这里我们可以自定义一个函数来求二叉树节点的个数

其次,这里要返回一个数组,数组里元素的顺序是二叉树前序遍历的顺序,所以这里我们要动态开辟一个数组.


5.2 代码实现🏁

根据上面两个思路我们可以写出这样的代码:

int TreeSize(struct TreeNode* root)//求二叉树节点个数的函数
 {
     return root==NULL?0:TreeSize(root->left)+TreeSize(root->right)+1;
 }
 int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
    int size=TreeSize(root);
    int* a=(int*)malloc(sizeof(int)*size);
    *returnSize=size;//将二叉树节点个数赋值给returnSize

这时求二叉树节点个数的函数,如果这里你不理解这个函数是怎么实现的,可以跳转二叉树详解,或者自己画递归展开图来理解.

写到这一步后,我们想要在数组中存储元素就要定义下标,而如果直接在要递归的函数中定义下标的话,每次递归后下标都会重置为0,就相当于每次都在操作数组里的第一个元素,所以这里我们采用了一个很巧妙的方式,将定义下标的位置写在递归函数外,并且将下标的地址传进函数,这样函数不管递归多少次下标都不会出问题:

int TreeSize(struct TreeNode* root)
 {
     return root==NULL?0:TreeSize(root->left)+TreeSize(root->right)+1;
 }

 void _preorderTraversal(struct TreeNode* root,int* a,int* pi)//递归的函数
 {
     if(root==NULL)//如果节点为空就直接返回
     {
         return;
     }
     a[(*pi)++]=root->val;//前序遍历,先将节点的值给数组a,再递归左右孩子
     _preorderTraversal(root->left,a,pi);
     _preorderTraversal(root->right,a,pi);

 }
int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
    int size=TreeSize(root);
    int* a=(int*)malloc(sizeof(int)*size);
    int i=0;//在接口函数中定义下标
    _preorderTraversal(root,a,&i);//将下标i的地址传入要递归的函数
    *returnSize=size;
    return a;//最后返回数组a的地址

}

当我们理解了前序遍历后,中后序遍历也就是将节点保存在数组中的位置的代码和遍历左右孩子的代码换一下就可以了! 中序遍历的链接:力扣94题 后序遍历的链接: 力扣145题


6. 总结🚩

这一部分的题用递归的方法比非递归更加容易写出代码,但是不好理解,所以画递归展开图是很有必要的.主要思想就是分治,大事化小小事化了.文章来源地址https://www.toymoban.com/news/detail-457814.html


到了这里,关于链式二叉树OJ题思路分享的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【链式二叉树】数据结构链式二叉树的(万字详解)

    前言: 在上一篇博客中,我们已经详解学习了堆的基本知识,今天带大家进入的是二叉树的另外一种存储方式----“链式二叉树”的学习,主要用到的就是“递归思想”!! 前情回顾: 再看二叉树基本操作前,再回顾下二叉树的概念,二叉树是: 空树 非空:根节点,根节点

    2024年01月20日
    浏览(39)
  • 【数据结构】二叉树(链式)

    😛作者:日出等日落 📘 专栏:数据结构           抱怨是一件最没意义的事情。如果实在难以忍受周围的环境,那就暗自努力练好本领,然后跳出那个圈子。 目录  🎄二叉树 ✔二叉树的结构:  ✔BuyNode(创建二叉树节点): 🎄基本函数操作: ✔PreOrder(前序递归遍历):

    2024年02月01日
    浏览(31)
  • 二叉树的链式存储

    2024年02月14日
    浏览(27)
  • 【数据结构】二叉树——链式结构

    目录  一、前置声明 二、二叉树的遍历 2.1 前序、中序以及后序遍历 2.2 层序遍历 三、节点个数以及高度 3.1 节点个数 3.2 叶子节点个数 3.3 第k层节点个数 3.4 二叉树的高度/深度 3.5 查找值为x的节点 四、二叉树的创建和销毁 4.1 构建二叉树 4.2 二叉树销毁 4.3 判断二叉树

    2024年02月16日
    浏览(31)
  • 【数据结构和算法】--- 二叉树(3)--二叉树链式结构的实现(1)

    在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构掌握还不够深入,且为了方便后面的介绍,此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研

    2024年01月25日
    浏览(45)
  • 数据结构(C语言实现)——二叉树的概念及二叉树顺序结构和链式结构的实现(堆排序+TOP-K问题+链式二叉树相关操作)

    前面学习了数据结构中线性结构的几种结构,顺序表,链表,栈和队列等,今天我们来学习一种非线性的数据结构——树。由于二叉树是数据结构中的一个重点和难点,所以本文着重介绍二叉树的相关概念和性质,以及二叉树的应用。 树是一种非线性的数据结构,它是由n(

    2023年04月21日
    浏览(35)
  • 【数据结构】二叉树链式结构

    🚀write in front🚀 📜所属专栏:初阶数据结构 🛰️博客主页:睿睿的博客主页 🛰️代码仓库:🎉VS2022_C语言仓库 🎡您的点赞、关注、收藏、评论,是对我最大的激励和支持!!! 关注我,关注我,关注我 , 你们将会看到更多的优质内容!!   在之前的二叉树的顺序结

    2024年02月03日
    浏览(27)
  • 二叉树创建并输入输出(链式结构)

          要进行二叉树的创建以及输入输出首先我们都应该遍历到二叉树各个结点才能进行相应的操作,二叉树的遍历方法一共有3种:    1.前序遍历(先结点,再左子树,再右子树)      2.中序遍历(先左子树,再结点,再右子树)      3.后序遍历(先左子树,再右子树,

    2024年02月06日
    浏览(25)
  • 【数据结构】二叉树的链式结构

    学习链式二叉树要知道三种遍历方式,便于对二叉树的节点以及左子树和右子树进行操作。 前序遍历:根、左子树、右子树 中序遍历:左子树、根、右子树 后序遍历:左子树、右子树、根 以下图为例: 得到的结果: 前序遍历:1 2 3 4 5 6 中序遍历:3 2 1 5 4 6 后序遍历:3 2

    2024年02月08日
    浏览(41)
  • 数据结构:链式二叉树初阶

    目录 一.链式二叉树的逻辑结构 1.链式二叉树的结点结构体定义 2.链式二叉树逻辑结构 二.链式二叉树的遍历算法 1.前序遍历 2.中序遍历 3.后序遍历  4.层序遍历(二叉树非递归遍历算法) 层序遍历概念: 层序遍历算法实现思路:  层序遍历代码实现: 三.链式二叉树遍历算法的运用

    2024年02月02日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包