【C/C++ 数据结构】-二叉树(2)

作者:学Java的冬瓜
博客主页:☀冬瓜的主页🌙
专栏:【C/C++ 数据结构和算法】

在这里插入图片描述

前言

今天的这篇博客,主要是二叉树的相关习题,包括笔试选择题,OJ题。对于二叉树的基本概念、求二叉树的特征,二叉树的性质,请看上一篇博客。

链接:
上篇博客:二叉树的基本概念及基本特征的求法

一、二叉树遍历选择题

1、前序+中序=》二叉树

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、后序+中序=》二叉树

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、OJ题

LeetCode题

题1:二叉树的前序遍历

链接:
LeetCode144.二叉树的前序遍历

法一:利用指针计算返回数组大小
int TreeSize(struct TreeNode* root)
{
    return root==NULL? 0 : TreeSize(root->left)+TreeSize(root->right)+1;
}

void _PrevOrder(struct TreeNode* root, int* a, int* pi)
{
    if(root==NULL)
    {
        return;
    }

    a[*pi] = root->val;
    (*pi)++;

    _PrevOrder(root->left, a, pi);
    _PrevOrder(root->right, a,pi);
}

//注意1:下面的struct TreeNode* root是输入型参数,int* returnSize是输出型参数
//因为只返回a不确定这个数组到底有多大,所以再设置一个输出型参数。
//达到返回两个数据的作用,从而确定空间的大小
int* preorderTraversal(struct TreeNode* root, int* returnSize)
{    
    //注意2:先计算这棵树的节点个数,从而确定数组大小
    int size=TreeSize(root);
    
    int* a = (int*)malloc(size*sizeof(int));
    
    //注意3:防止每次递归都创建a空间,所以不调用自己,另外用一个函数实现递归遍历
    int i=0;
    _PrevOrder(root, a, &i);
    
    //注意4:设置输出型参数,返回两个数据,从而确定数组大小
    *returnSize=i;
    return a;
}
法二:利用全局变量计算数组大小

注意:
1、因为有多组测试用例,每次使用完全局变量,都需要置0
2、如果用局部变量统计数组个数,那么递归中归的时候i是上一层的i,而不是下一层计算过后的i。

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

int i=0;
void _PrevOrder(struct TreeNode* root, int* a)
{
    if(root==NULL)
    {
        return;
    }

    a[i] = root->val;
    i++;

    _PrevOrder(root->left, a);
    _PrevOrder(root->right, a);
}


int* preorderTraversal(struct TreeNode* root, int* returnSize){
    //注意重点1:因为有多组测试用例,所以用全局变量统计数组元素个数
    //在每一个用例使用完后,这个全局变量都需要置0
    i=0;

    int size=TreeSize(root);
    int* a = (int*)malloc(size*sizeof(int));

    _PrevOrder(root, a);

    *returnSize=i;
    return a;
}

题2:二叉树的中序遍历

链接:
LeetCode94.二叉树的中序遍历

说明:和前序遍历一样,用了指针计算数组大小,然后去访问

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

void _PrevOrder(struct TreeNode* root, int* a, int* pi)
{
    if (root == NULL)
        return;


    _PrevOrder(root->left, a, pi);

    a[*pi] = root->val;
    (*pi)++;

    _PrevOrder(root->right, a, pi);
}

int* inorderTraversal(struct TreeNode* root, int* returnSize)
{
    int size = TreeSize(root);
    int* a = (int*)malloc(size * sizeof(int));

    int i = 0;
    _PrevOrder(root, a, &i);

    *returnSize = i;
    return a;
}

题3:二叉树的后序遍历

链接:
LeetCode145.二叉树的后序遍历

说明:和前序遍历一样,用了指针来表示数组大小,然后去访问

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

void _PostOrder(struct TreeNode* root, int* a, int* pi)
{
    if(root==NULL)
        return;

    _PostOrder(root->left, a, pi);
    _PostOrder(root->right, a, pi);

    a[*pi] = root->val;
    (*pi)++;
}

int* postorderTraversal(struct TreeNode* root, int* returnSize){
    int size = TreeSize(root);
    int* a = (int*)malloc(size*sizeof(int));

    int i=0;
    _PostOrder(root, a, &i);

    *returnSize = i;
    return a;
}

题4:平衡二叉树

链接:
LeetCode110.平衡二叉树

说明:平衡二叉树通俗来讲就是这棵树的节点分布均匀。在规律上:
一棵平衡二叉树,每个结点的左右子树的高度差的绝对值不超过1

思路

  1. 根节点开始判断,左右子树的高度差,不大于1,然后再进入子树的检查
  2. 遇到NULL前全都符合高度差不大于1,则开始归。如果高度差大于1,那么直接层层返回false
  3. 如果递归完都符合,那就是到了最开始的根节点处的return那一行,都为真。即return true。完全符合条件。
int maxDepth(struct TreeNode* root)
{
    if(root==NULL)
        return 0;

    int leftdepth = maxDepth(root->left);
    int rightdepth = maxDepth(root->right);

    return leftdepth>rightdepth ? leftdepth+1 : rightdepth+1;
}

//判断是否是平衡二叉树:需要计算当前节点的左右子树的高度差是否小于2,然后利用分治原理
bool isBalanced(struct TreeNode* root){
    //注意3:
    //1>当从树的根节点检查到叶节点都符合条件,
    //然后检查到叶节点的下一层为NULL,那么这棵子树是符合条件的
    //2>如果最开始的根节点root==NULL,那也是返回true
    if(root==NULL)
        return true;

    //注意1:当前节点不为空,就计算它的左右子树高度差
    int leftdepth = maxDepth(root->left);
    int rightdepth = maxDepth(root->right);

    //注意2:判断左右子树的高度差是否符合条件
    //不符合就直接返回false,符合条件则进入递归,进行子树的检查
    return (abs(leftdepth-rightdepth) < 2 
    && isBalanced(root->left) 
    && isBalanced(root->right));
}

牛客题

题5:二叉树的遍历

链接:
牛客.二叉树的遍历

要求:根据前序遍历(+#表示空)的字符串,创建二叉树,并完成中序遍历

思路

  1. pi(传址调用)来作为字符串下标,防止字符归时重复访问。
  2. 先判断当前字符,不是#,开始创建树的节点,然后该节点的left和right=递归创建树函数,开始进入递归。
  3. 每次当前节点的左右子树都创建完(以NULL为叶子节点的left和right)后。就返回当前节点,让上一层的调用来接收
  4. 如果遇到了#,说明这棵树在这个节点的方向已经完成,return NULL,让上一层调用接收。
#include <stdio.h>
#include <stdlib.h>

typedef char TDataType;
typedef struct TreeNode
{
    TDataType val;
    struct TreeNode* left;
    struct TreeNode* right;
}TreeNode;

//重点1:
//创建二叉树,要用到递归,除了传二叉树的根节点,还要用pi(统计)来保证str字符串在归时
//str指针指向的字符不会回到之前的字符
//从而保证一个一个字符的访问,每个字符只访问一次
TreeNode* CreatTree(char* str, int* pi)
{
    //重点5:当遇到字符#时,表示上一个节点的当前子树为NULL
    //完成最开始的递归中的递,然后归,然后可能递可能归。
    if(str[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }
    
    //重点2:当str字符串当前字符为有效字符(不为#)时,创建树的节点,
    //并把当前字符赋值给节点的val
    TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));
    if(root==NULL)
    {
        printf("malloc fail\n");
        exit(-1);
    }
    
    root->val = str[*pi];
    (*pi)++;
    
    //重点3:创建新的节点后,开始进入递归,创建这个节点的左右子树
    root->left = CreatTree(str, pi);
    root->right = CreatTree(str, pi);
    
    //重点4:当前这个节点及其左右子树创建完成后,返回该节点
    return root;
}

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

int main()
{
    char str[100];
    scanf("%s",str);
    int i = 0;
    TreeNode* tree = CreatTree(str, &i);
    InOrder(tree);
    return 0;
}

最后:大家国庆快乐啊!今天女篮虽然没有打赢,但她们站在赛场上的那一刻,我就觉得已经是胜利了,真的很棒!希望祖国更加繁荣富强,也希望大家都越来越好!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

学Java的冬瓜

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

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

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

打赏作者

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

抵扣说明:

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

余额充值