数据结构初阶之二叉树(4)

目录

二叉树OJ练习

单值二叉树

思路

实现

检查两颗树是否相同

思路

实现

对称二叉树

思路

实现

二叉树的前序遍历

思路

实现

二叉树中序遍历

思路

实现

二叉树的后序遍历

思路

实现

另一颗树的子树

思路

实现


二叉树OJ练习

单值二叉树

力扣965. 单值二叉树

如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。

只有给定的树是单值二叉树时,才返回 true;否则返回 false

提示:

  1. 给定树的节点数范围是 [1, 100]
  2. 每个节点的值都是整数,范围为 [0, 99] 。

思路

首先判断整个树的节点的值是否相等,可以将整个二叉树拆分成多个子树,每个子树只需要堆根节点,左子节点,右子节点进行比较,相等关系的比较可以间接获得,如a=b,a=c可以推断a=c。因此每个子树只要根节点的值等于左节点的值,根节点的值等于右节点的值,整个子树就是单值子树。

其次二叉树中可能出现空节点的情况(题目中祖先节点必不为空,所以不考虑组先节点),简化如下:

 当节点为空时,不需要判断,所以判断之前要子节点先进行不为空判断,然后再判断值。

最后时返回值,

返回分为三个部分。

一、不相等时返回:整个题目中如果出现一次判断不相等,后续的程序不需要进行,所以不相等时返回false,如果相等则继续递归。

二、相等时返回:相等时需要继续向下递归,直到递归完整棵树,所以当子树的根节点为空时说明被判断过的子树的值完全相等。

三、左子树与右子树的值是否相等,递归时一次只能递归一棵子树,所以最终的结果需要左子树与右子树的结果逻辑与之后才能判断。

实现

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


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

检查两颗树是否相同

力扣https://leetcode.cn/problems/same-tree/

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

提示:

  • 两棵树上的节点数目都在范围 [0, 100] 内
  • -104 <= Node.val <= 104

思路

判断是否相同的两棵树需要从两个方面判断值与结构,简化如下:

同样的将整个二叉树划分为由根节点,左子树,右子树组成的子树,当两个子树之间结构相等,值相等时两个子树完全相等。

对子树的判断本质上也是对根节点的判断,当根节点相等时才会继续判断左子树的节点,左子树的节点完全相同时判断右子树的节点,左右子树的节点本身也可以看作根节点,所以只需要化简为对根节点的判断。

判断的过程,程序递归判断,相同时继续递归直到节点为空说明所遍历过的节点相等,可以返回真值,如果不同则返回假。

实现

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


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;
    }
    return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);

}

对称二叉树

101. 对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

思路

根据题目的意思,组先节点不用判断,因此判断一个数是否对称,可以理解为判断两个数是否为镜像。

对称的判断需要对值和结构进行判断:

值的判断:

P树的左根节点的值等于Q树的右根节点的值,两者相等。

结构的判断:

P,Q同时为空或者同时不为空时两者结构相等,P为空Q不为空或者相反时,两者结构不相等。

子树完全相等返回值:

P,Q递归到空时,说明之前的节点相等,因此返回true,其余的情况返回false。

实现

为了避开对祖先节点的影响,所以另写一个函数对子树进行判断。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


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



bool isSymmetric(struct TreeNode* root)
{
  return isTree(root->left,root->right);
}

二叉树的前序遍历

144. 二叉树的前序遍历

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

思路

本题目要求用前序遍历的顺序将二叉树中节点的值放在数组中返回,因为数组的大小不确定,所以需要先遍历二叉树的节点确定数组的大小,或者直接开辟超大数组也可以(不过这样有点浪费)。开辟数组后,前序遍历二叉树,当二叉树节点不为空时,把值放入数组,为空时返回,需要注意传递数组下标时不能使用传值方式,必须使用传址的方式。

实现

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

int preorderOrder(struct TreeNode* root)
{
    if(root==NULL)
    {
        return 0;
    }

    return 1+preorderOrder(root->left)+preorderOrder(root->right);
}

void preorder(struct TreeNode* root,int* capacity,int *returnSize)
{
    if(root==NULL)
    {
        return ;
    }
    capacity[*returnSize]=root->val;
    (*returnSize)++;
    preorder(root->left,capacity,returnSize);
    preorder(root->right,capacity,returnSize);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
    *returnSize=0;
    int num=preorderOrder(root);
    int *capacity=(int *)malloc(sizeof(int)*num);
    assert(capacity);
    preorder(root,capacity,returnSize);
    return capacity;
}

二叉树中序遍历

94. 二叉树的中序遍历

思路

与前序一样。

实现

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

 /**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

int preorderOrder(struct TreeNode* root)
{
    if(root==NULL)
    {
        return 0;
    }

    return 1+preorderOrder(root->left)+preorderOrder(root->right);
}

void inorder(struct TreeNode* root,int* capacity,int *returnSize)
{
    if(root==NULL)
    {
        return ;
    }
    inorder(root->left,capacity,returnSize);
    capacity[*returnSize]=root->val;
    (*returnSize)++;
    inorder(root->right,capacity,returnSize);
}

int* inorderTraversal(struct TreeNode* root, int* returnSize)
{
     *returnSize=0;
    int num=preorderOrder(root);
    int *capacity=(int *)malloc(sizeof(int)*num);
    assert(capacity);
    inorder(root,capacity,returnSize);
    return capacity;

}

二叉树的后序遍历

思路

与前序,中序相同。

实现

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

 /**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

 /**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

int preorderOrder(struct TreeNode* root)
{
    if(root==NULL)
    {
        return 0;
    }

    return 1+preorderOrder(root->left)+preorderOrder(root->right);
}

void postorder(struct TreeNode* root,int* capacity,int *returnSize)
{
    if(root==NULL)
    {
        return ;
    }
    postorder(root->left,capacity,returnSize);
    postorder(root->right,capacity,returnSize);
    capacity[*returnSize]=root->val;
    (*returnSize)++;
}


int* postorderTraversal(struct TreeNode* root, int* returnSize)
{
      *returnSize=0;
    int num=preorderOrder(root);
    int *capacity=(int *)malloc(sizeof(int)*num);
    assert(capacity);
    postorder(root,capacity,returnSize);
    return capacity;
}

另一颗树的子树

572. 另一棵树的子树

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/subtree-of-another-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

判断另一棵树与子树相等,本质上时对两棵树的判断,因此需要将整个问题拆分成两部分,一是对两棵树的判断,二是递归新的子树与另一棵树判断。

对两棵树的判断可以参考前面对两个数判断的题目,这里主要说明传递新树的部分:

传递新树本质是传递根节点,因此传递新数可以采用递归左子树与递归右子树的方式,如果相同返回真,如果不同继续递归新的节点,该题目中真是唯一确认的条件,因此当传递的根节点为空时,说明没有找到相同的子树,所以返回假。同时题目需要对两颗子树进行判断,所以最终的结果时左子树与右子树判断的结果逻辑或(利用逻辑或短路运算的优势,如果左子树为真则不需要判断右子树)。

 

实现

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

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


bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{
    if(root==NULL)
    {
        return false;
    }
    if(issametree(root,subRoot))
    {
        return true;
    }
    else
    {
        return isSubtree(root->left, subRoot)||isSubtree(root->right, subRoot);
    }
    

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值