【数据结构】——二叉树OJ题

文章目录

    • 前言
    • [1. 单值二叉树](#1. 单值二叉树)
    • [2. 检查两颗树是否相同](#2. 检查两颗树是否相同)
    • [3. 判断一棵树是否为另一颗树的子树](#3. 判断一棵树是否为另一颗树的子树)
    • [4. 对称二叉树](#4. 对称二叉树)
    • [5. 平衡二叉树](#5. 平衡二叉树)
    • [6. 二叉树的前序遍历](#6. 二叉树的前序遍历)
    • [7. 二叉树的中序遍历](#7. 二叉树的中序遍历)
    • [8. 二叉树的后序遍历](#8. 二叉树的后序遍历)
    • [9. 二叉树的构建及遍历](#9. 二叉树的构建及遍历)

前言

我们先想想二叉树我们学习了哪些内容再来做题哈

其实学习二叉树重要的思想------递归,我们可以通过后面的题目慢慢的理解

1. 单值二叉树

OJ链接:965. 单值二叉树 - 力扣(LeetCode)

好的,我们一起来看一下题目,题目是这样说的

题目描述

如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树,只有给定的树是单值二叉树时,才返回 true;否则返回 false

示例

思路分析

我们想一下,单值二叉树是不是一棵树的所有节点的值都相同,当且仅当对于树上的每一个子树的两个孩子,它们也都有相同的值

因此,我们可以对树进行一次深度优先搜索,当搜索到节点root时,我们检查root的左孩子和右孩子是否相同,不相同则返回false,直到检查了所有的节点,所以我们就可以进行递归遍历,每次比较根节点和左右孩子的val值是否相等,不相等就返回false,然后递归比较左子树和右子树

C 复制代码
bool isUnivalTree(struct TreeNode* root) {
    if(root == NULL)
        return true;
    if(root->left && root->val != root->left->val)
        return false;
    if(root->right && root->val != root->right->val)
        return false;
    return isUnivalTree(root->left) && 
        isUnivalTree(root->right);
}

我们现在来尝试画一下递归展开图,更方便我们理解

[3,3,3,null,null,2,3] 举例

2. 检查两颗树是否相同

OJ链接:100. 相同的树 - 力扣(LeetCode)

好的,我们一起来看一下题目,题目是这样说的

题目描述

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

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

示例

思路分析

我们先可以想象一下,如果两棵树相同的话,应该会有哪些情况

如果两个树都是空树的话,就是相同的,那如果一棵树是空树,另一颗不是空树,那肯定不是相同的

如果两个二叉树都不为空,那么首先判断它们的根节点的值是否相同,若不相同则两个二叉树一定不同,若相同,再分别判断两个二叉树的左子树是否相同以及右子树是否相同。这是一个递归的过程,因此可以使用深度优先搜索,递归地判断两个二叉树是否相同

c 复制代码
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);
}

这个递归展开和上一个题一样,我们就不画了,留给大家画一下哈

3. 判断一棵树是否为另一颗树的子树

OJ链接:572. 另一棵树的子树 - 力扣(LeetCode)

好的,我们一起来看一下题目,题目是这样说的

题目描述

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

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

示例

思路分析

由于root和subRoot中可能含有一个和多个值相同的节点,所以判断不相等的时候,又要返回原来的根节点,所以我们可以这道题利用上一题的代码,我们的思路为不断的比较root这棵树以每一个节点作为根节点,判断是否和subRoot相等,相等就返回true,所有节点都遍历之后都没有相等的树就返回false

C 复制代码
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. 对称二叉树

OJ链接:110. 平衡二叉树 - 力扣(LeetCode)

好的,我们一起来看一下题目,题目是这样说的

题目描述

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

示例

思路分析

这道题和判断两棵树是否相等的思路一致,只是有一些细节有所不同。

对称二叉树是最左边和最右边的节点相同,所以我们就可以拿第一棵树的左子树和第二棵树的右子树进行比较,拿第一棵树的右子树和第二棵树的左子树进行比较,不相同就返回false,相同就继续比较,直到所有节点比较完成

C 复制代码
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->right) &&
    	isSameTree(p->right,q->left);
}

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

5. 平衡二叉树

OJ链接:110. 平衡二叉树 - 力扣(LeetCode)

好的,我们一起来看一下题目,题目是这样说的

题目描述

给定一个二叉树,判断它是否是 平衡二叉树

平衡二叉树 是指该树所有节点的左右子树的深度相差不超过 1。

示例

思路分析

这道题中的平衡二叉树的定义是:二叉树的每个节点的左右子树的高度差的绝对值不超过 1,则二叉树是平衡二叉树。根据定义,一棵二叉树是平衡二叉树,当且仅当其所有子树也都是平衡二叉树,因此可以使用递归的方式判断二叉树是不是平衡二叉树

对于当前遍历到的节点,首先计算左右子树的高度,如果左右子树的高度差是否不超过 1,再分别递归地遍历左右子节点,并判断左子树和右子树是否平衡。这是一个自上而下的递归的过程

C 复制代码
int Rootheight(struct TreeNode* root){
    if(root == NULL)
        return 0;
    else
        return fmax(Rootheight(root->left),Rootheight(root->right)) + 1;
}

bool isBalanced(struct TreeNode* root) {
    if(root == NULL)
        return true;
    else
        return fabs(Rootheight(root->left) - Rootheight(root->right)) <=1
    && isBalanced(root->left) && isBalanced(root->right);
}

6. 二叉树的前序遍历

OJ链接:144. 二叉树的前序遍历 - 力扣(LeetCode)

好的,我们一起来看一下题目,题目是这样说的

题目描述

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

示例

思路分析

二叉树的前序遍历我们已经非常熟悉,这里需要注意:

  1. 由于二叉树的节点数是未知的,为了不浪费空间,我们可以先求出二叉树的节点数,然后开辟对应大小的空间
  2. 由于数据存储在一个数组中,所以我们需要一个变量i来控制数组的下标,由于在递归调用的过程中对形参的改变不会改变影响实参,所以这里我们需要传递i的地址
C 复制代码
int TreeSize(struct TreeNode* root)
{
    if(root == NULL)
        return 0;
    else
        return TreeSize(root->left) + TreeSize(root->right) + 1;
}

void preorder(struct TreeNode* root, int* a, int* pi)
{
    if(root == NULL)
        return;
    a[*pi] = root->val;
    (*pi)++;
    preorder(root->left,a,pi);
    preorder(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;
    preorder(root,a,&i);
    *returnSize = size;
    return a;
}

那让我们看看前序遍历的递归展开图

7. 二叉树的中序遍历

OJ链接:94. 二叉树的中序遍历 - 力扣(LeetCode)

好的,我们一起来看一下题目,题目是这样说的

题目描述

给定一个二叉树的根节点 root ,返回它的 中序 遍历 。

示例

二叉树的中序遍历和前序遍历一样,只是访问节点的顺序不同

代码实现如下

C 复制代码
int TreeSize(struct TreeNode* root)
{
    if(root == NULL)
        return 0;
    else
        return TreeSize(root->left) + TreeSize(root->right) + 1;
}

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

int* inorderTraversal(struct TreeNode* root, int* returnSize) {
    int size = TreeSize(root);
    int* a = (int*)malloc(sizeof(int) * size);
    int i = 0;
    preorder(root,a,&i);
    *returnSize = size;
    return a;
}

8. 二叉树的后序遍历

OJ链接:145. 二叉树的后序遍历 - 力扣(LeetCode)

好的,我们一起来看一下题目,题目是这样说的

题目描述

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历

示例

二叉树的中序遍历和前序遍历一样,只是访问节点的顺序不同

代码实现如下

C 复制代码
int TreeSize(struct TreeNode* root)
{
    if(root == NULL)
        return 0;
    else
        return TreeSize(root->left) + TreeSize(root->right) + 1;
}

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

int* postorderTraversal(struct TreeNode* root, int* returnSize) {
    int size = TreeSize(root);
    int* a = (int*)malloc(sizeof(int) * size);
    int i = 0;
    preorder(root,a,&i);
    *returnSize = size;
    return a;
}

9. 二叉树的构建及遍历

OJ链接:二叉树遍历_牛客题霸_牛客网 (nowcoder.com)

好的,我们一起来看一下题目,题目是这样说的

题目描述

编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中"#"表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

输入描述:

输入包括1行字符串,长度不超过100。

输出描述:

可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。 每个输出结果占一行。
示例

思路分析

这道题目是前序建立二叉树和中序遍历,我们写成两个子函数即可,对于二叉树的创建,字符为'#'说明节点为空,我们直接返回即可,然后依次递归创建节点即可

代码实现如下

C 复制代码
#include <stdio.h>
#include <stdlib.h>

typedef char BTDataType;
typedef struct BinaryTreeNode
{
    BTDataType data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
} BTNode;

// 构建二叉树
BTNode* BTreeCreate(char* a, int* pi)
{
    if (a[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }
    // 创建根节点
    BTNode* root = (BTNode*)malloc(sizeof(BTNode));
    if (root == NULL) 
    {
        perror("malloc fail");
        exit(-1);
    }
    root->data = a[*pi];
    (*pi)++;
    // 创建左子树和右子树
    root->left = BTreeCreate(a, pi);
    root->right = BTreeCreate(a, pi);
    return root;
}
// 二叉树中序遍历
void InOrder(BTNode* root)
{
    if (root == NULL)
    {
        return;
    }
    // 先访问左子树,再访问根节点,最后访问右子树
    InOrder(root->left);
    printf("%c ", root->data);
    InOrder(root->right);
}

int main()
{
    char str[100];
    scanf("%s", str);
    // 创建二叉树
    int i = 0;
    BTNode* root = BTreeCreate(str, &i);
    // 二叉树的中序遍历
    InOrder(root);

    return 0;
}
相关推荐
CoderIsArt36 分钟前
Redis的三种模式:主从模式,哨兵与集群模式
数据库·redis·缓存
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
师太,答应老衲吧3 小时前
SQL实战训练之,力扣:2020. 无流量的帐户数(递归)
数据库·sql·leetcode
Peter_chq3 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
wheeldown4 小时前
【数据结构】选择排序
数据结构·算法·排序算法
Channing Lewis4 小时前
salesforce case可以新建一个roll up 字段,统计出这个case下的email数量吗
数据库·salesforce
aloha_7894 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
hikktn5 小时前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust
观音山保我别报错5 小时前
C语言扫雷小游戏
c语言·开发语言·算法
毕业设计制作和分享5 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis