【数据结构初阶-oj】入门二叉树的入门oj

前言

本期带来二叉树入门oj题的分享,写二叉树的题,最重要的就是分治思想

博主水平有限,不足错漏之处,望请斧正,感激不胜!

1. 单值二叉树

思路

在这里插入图片描述

每个结点值相等…

根 = 左子树 && 根 = 右子树,等量代换: a = b && b = c ==> a = c

所有只需要根 = 左子树 && 根 = 右子树,就满足单值二叉树

代码

bool isUnivalTree(struct TreeNode* root)
{
    if(root == NULL)
        return true;

    if(root->left != NULL && root->left->val != root->val)
        return false;
    if(root->right != NULL && root->right->val != root->val)
        return false;
    
    return isUnivalTree(root->left) && isUnivalTree(root->right);
}

代码分析:

  • 判断时,只判断能出结果的条件——不等则返回假,相等不用管,继续走
  • 还需要考虑结构:左/右子树不为空就比,为空肯定就不比了

2. 相同的树

在这里插入图片描述

思路

结构相同,结点值相等…

分:

  1. 判断值:根值等 && 左子树值等 && 右子树值等
  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;
    
    return isSameTree(p->left, q->left)
        && isSameTree(p->right,q->right);
}

代码分析:

  • 判断结构:
    • 两个都到空,满足结构相等
    • 只有一个到空,结构不等
  • 判断值
  • 满足pq的左子树相同 && pq的右子树相同

3.另一棵树的子树

在这里插入图片描述

思路

前序遍历,每次拿到的根传给 IsSameTree,判断相等

代码

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

}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{
    if(root == NULL)
        return false;

    if(isSameTree(root, subRoot))
        return true;
    
    return isSubtree(root->left, subRoot)
        || isSubtree(root->right, subRoot);
}

代码分析:

  • 这里的返回要求的不是两边都有子树了,而是找到一颗就够 —— 逻辑或

4. 翻转二叉树

在这里插入图片描述

思路

根的左右子树交换 ==> 左子树的左右子树交换,右子树的左右子树交换…

分:左右子树交换

治:递归交换左右子树

代码

struct TreeNode* invertTree(struct TreeNode* root)
{
    //递归交换左右子树
    if(root == NULL)
        return NULL;
    struct TreeNode* tmp = root->left;
    root->left = root->right;
    root->right = tmp;

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

    return root;
}

代码分析:

  • 即使左右子树交换了也不影响后续的交换:交换只在本根结点的子树内,和兄弟结点的子树互不影响

5.对称二叉树

在这里插入图片描述

思路

根结点没有对称可言,所以对称的判断从根结点的左右子树开始

如何判断对称?假设我们拿到图中 左2 和 右2:

  1. 判断他俩的值和结构
  2. 判断 左2 的左子树和 右2 的右子树 ,再判断 左2 的右子树和 右2 的左子树

分:判断根结点和子树

治:递归判断 左的左和 右的右 && 左的右 和 右的左

代码

bool Compare(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 Compare(left->left, right->right)
        && Compare(left->right, right->left);
    
}

bool isSymmetric(struct TreeNode* root)
{
    return Compare(root, root);
}

代码分析:

  • 比值和结构和翻转二叉树类似
  • 初始状态直接传root和root,而后递归 左的左和 右的右 && 左的右 和 右的左

6.平衡二叉树

思路

abs(左子树高度 - 右子树高度) >= 1,递归判断每棵子树

代码

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

    int lh = TreeHeight(root->left);
    int rh = TreeHeight(root->right);

    return lh > rh ? lh+1 : rh+1;
}

bool isBalanced(struct TreeNode* root)
{
    if(root == NULL)
        return true;
        
    //每个根的左右高度绝对值 <=1
    if(abs(TreeHeight(root->left) - TreeHeight(root->right)) > 1)
        return false;

    return isBalanced(root->left)
        && isBalanced(root->right);
}

代码分析:

  • 求树的高度再上一篇博客实现过
  • 要求左右都满足平衡——逻辑与

7.二叉树的前序遍历

在这里插入图片描述

思路

前序遍历没什么问题,只不过这道题的接口要求我们把每个结点值放进数组

代码

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

void PreOrder(struct TreeNode* root, int* arr, int* pi)
{
    //遍历,并放到数组内
    if(root == NULL)
        return;

    //root ==> left ==> right
    arr[*pi] = root->val;
    (*pi)++;

    PreOrder(root->left, arr, pi);
    PreOrder(root->right, arr, pi);

}

int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
    int n = TreeSize(root);
    int* arr = (int*)malloc(sizeof(int) * n);
    *returnSize = n;
    int i = 0;

    PreOrder(root, arr, &i);

    return arr;
}

代码分析

  • 和之前实现的前序遍历,区别仅在“输出”
  • 中序后序同理

8.二叉树遍历

在这里插入图片描述

思路

输入的字符串为前序遍历字符串,根据它来建树就是:根 ==> 左 ==> 右,每次拿到新的一个字符放进根,再递归左子树右子树

最后中序遍历输出即可

代码

#include <stdio.h>
#include <stdlib.h>
typedef char BTDataType;
typedef struct BTNode
{
    BTDataType val;
    struct BTNode* left;
    struct BTNode* right;
}BTNode;

BTNode* BuildTree(char* s, int* pi)
{
    if(s[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }

    BTNode* root = (BTNode*)malloc(sizeof(BTNode));
    root->val = s[(*pi)++];
    root->left = BuildTree(s, pi);
    root->right = BuildTree(s, pi);
    
    return root;
}

void InOrder(BTNode* root)
{
    if(root == NULL)
        return;
    
    InOrder(root->left);
    printf("%c ", root->val);
    InOrder(root->right);
}

int main() 
{
    char s[101];
    scanf("%s", s);
    int i = 0;
    BTNode* root = BuildTree(s, &i);
    InOrder(root);
}

代码分析

  • 访问字符串需要留意,这里我们用 数组名+下标 的方式访问字符串
    • 下标在传参时传地址(每次用完一个字符往下走,需要改变下标的值)

今天的分享就到这啦,这里是培根的blog,期待与你共同进步!

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周杰偷奶茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值