二叉树基础OJ题(二叉树的遍历、分治算法、数据结构、C语言)


前言:

  • 在学习完二叉树的基本知识后,主要包括前序遍历以及分治算法的思想,再通过下面几道基础OJ题提高理解
  • 题目来源:LeetCode、牛客
  • 代码:C语言

1. 单值二叉树

LeetCode链接:单值二叉树

1.1 题目描述及解决思路

在这里插入图片描述


  • 解决思路1:利用前序遍历,从根结点开始,以根节点的date为标准值,以此和各个结点的date比较,控制返回bool值即可
  • 解决思路2:利用前序遍历,从根结点开始,每次都以根节点的date为标准值,以此和它的左右孩子的date比较
1.2 AC代码
  • 利用全局变量,不带返回值
bool flag = true;

void PreOrderCompare(struct TreeNode* root, int val)
{
    if(root == NULL || flag == false)//优化
        return;

    if (root->val != val)
    {
        flag = false;
        return;
    }
        

    PreOrderCompare(root->left, val);
    PreOrderCompare(root->right, val);
}

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

    flag = true;//全局遍历,每次调用前重置
    PreOrderCompare(root, root->val);
    return flag;
}

  • 带返回值
bool isUnivalTree(struct TreeNode* root){
    if(root == NULL)
        return true;
    
    if(root->left && root->left->val != root->val)
        return false;

    if(root->right && root->right->val != root->val)
        return false;

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

2. 相同的树

LeetCode链接:相同的树

2.1 题目描述及解决思路


  • 解决思路:利用前序遍历分治思想,把每颗树分成根和左子树、右子树,以此进行比较,若根相等,则比较他们的左右子树,左右子树又重新看做一颗新的树,分成根和左右子树,继续重复比较步骤,层层递归下去
2.2 AC代码
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. 对称二叉树

LeetCode链接:对称二叉树

3.1 题目描述及解决思路

在这里插入图片描述


  • 解决思路:利用前序遍历分治思想,对每一颗树,进行左子树和右子树的比较,对于子树,再继续分划,分成下一个左右子树的比较
3.2 AC代码
bool isSymmetricSubTree(struct TreeNode* root1, struct TreeNode* root2)
{
    if(root1 == NULL && root2 == NULL)
        return true;

    if(root1 == NULL || root2 == NULL)
        return false;

    if(root1->val != root2->val)
        return false;
    
    return isSymmetricSubTree(root1->left, root2->right)
        && isSymmetricSubTree(root1->right, root2->left);
}

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

    return isSymmetricSubTree(root->left, root->right);
}

4. 另一棵树的子树(*)

LeetCode链接:另一棵树的子树

4.1 题目描述及解决思路

在这里插入图片描述


  • 解决思路:利用前序遍历分治思想,把原树中所有子树都找出来和subRoot比较一下,就可以了,比较可以调用上面相同的树的代码。这里的问题在于如何找出所有子树。
4.2 AC代码
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);
}

5. 二叉树的前序遍历

LeetCode链接:二叉树的前序遍历

5.1 题目描述及解决思路

这里是引用

在这里插入图片描述


  • 解决思路:前序遍历,先求出二叉树的结点个数,malloc一个数组,将有效数据存入,再返回该数组
5.2 AC代码
int TreeSize(struct TreeNode* root)
{
    return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

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

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

    return a;
}

6. 二叉树的中序遍历

LeetCode链接:二叉树的中序遍历

6.1 题目描述及解决思路

在这里插入图片描述


  • 解决思路:和前面的前序遍历一样,只是修改遍历的顺序,基本思路是一样的
6.2 AC代码
int TreeSize(struct TreeNode* root)
{
    return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

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

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

    return a;
}

7. 二叉树的后序遍历

LeetCode链接:二叉树的后序遍历

7.1 题目描述及解决思路

在这里插入图片描述


  • 解决思路:和前面的前序遍历一样,只是修改遍历的顺序,基本思路是一样的
7.2 AC代码
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;
}

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

    return a;
}

8. 二叉树的构建及遍历

牛客链接:二叉树的构建及遍历

8.1 题目描述及解决思路

在这里插入图片描述


  • 解决思路:利用前序遍历,逐步构建一个二叉树,然后对二叉树进行中序遍历,输出遍历结果
    在这里插入图片描述
8.2 AC代码
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int BTDateType;
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	BTDateType date;
}BTNode;

BTNode* BuyNode(BTDateType x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	assert(node);

	node->date = x;
	node->left = NULL;
	node->right = NULL;

	return node;
}

BTNode* CreateTree(char* str, int* pi)
{
    if(str[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }
    
    BTNode* root = BuyNode(str[(*pi)++]);
    root->left = CreateTree(str, pi);
    root->right = CreateTree(str, pi);
    
    return root;
}

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

int main()
{
    char str[100];
    scanf("%s",str);
    int i=0;
    //前序构建
    BTNode* root = CreateTree(str, &i);
    
    //中序遍历
    InOrder(root);
    
    return 0;
}

学习记录:

  • 本篇博客整理于2022.7.7
  • 请多多指教🌹
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

如何写出最优雅的代码

感谢支持,我将继续努力!

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

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

打赏作者

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

抵扣说明:

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

余额充值