二叉树基础OJ题

前言

二叉树学到现在,我们对递归已经一定程序上的理解了,所有这里为了加深我们对二叉树递归的掌握,我会分享几道基础的练习题来巩固加深我们对二叉树的理解

这里拿出一些二叉树OJ题,我会写出过程详解,如有错误还望指正!题源来自于牛客网和力扣

单值二叉树

这题需要判断每个节点的值是否相同,当根结点的值等于左子树,根结点的值右子树时,左子树等于右子树,那么我们只需要判断于左右节点与根节点的值是否相同就可以了,我们这里的思路是先判断这颗树是否为空,空树也是单值二叉树。如果左右节点的值与它们的根节点不相同,则这棵树不是单值二叉树,返回false,如果能一直遍历到二叉树最底层,则返回true

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

相同的树

如果两棵树都为空,都为空树,则相同返回true,如果只有一棵树为空,另一棵树不为空,则不相同返回false,继续判断两棵树的左右子树的值是否相同,不相同则返回false,相同则继续走,直到树底为止

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

二叉树的前序遍历

题目要求我们将二叉树前序遍历的结果输出出来并且不能使用递归的方法,我们可以将二叉树前序遍历的结果先放到数组中在将数组输出,先求出二叉树的大小,在动态开辟二叉树大小的空间存放数据,然后前序遍历二叉树就可以了,这里注意在preorder函数中pi需要使用指针,因为形参不改变实参,二叉树的中序遍历和后序遍历只需要改动preorder数组就行了,道理还是和前序遍历一样

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(sizeof(int) * (*returnSize));
    if(NULL == a)
    {
        return NULL;
    }    

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

    for(i = 0; i < *returnSize; ++i)
    {
        printf("%d ", a[i]);
    }

    return a;
}

二叉树中序遍历

思路与前序遍历一样

int SizeTree(struct TreeNode* root)
{
    return root == NULL ? 0 : SizeTree(root->left) + 
                    SizeTree(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 = SizeTree(root);
    int* a = (int*)malloc(sizeof(int) * (*returnSize));
    if(NULL == a)
    {
        return NULL;
    }

    int i = 0;
    inorder(root, a, &i);
    for (i = 0; i < *returnSize; ++i)
    printf("%d ", a[i]);

    return a;
}

二叉树后续遍历

int SizeTree(struct TreeNode* root)
{
    return root == NULL ? 0 : SizeTree(root->left) + 
                    SizeTree(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 = SizeTree(root);
    int* a = (int*)malloc(sizeof(int) * (*returnSize));
    if(NULL == a)
    {
        return NULL;
    }

    int i = 0;
    postorder(root, a, &i);
    for (i = 0; i < *returnSize; ++i)
    printf("%d ", a[i]);

    return a;
}

二叉树遍历

我们可以通过题目给的条件以中序遍历的顺序将它的二叉树大致情况画出来,然后将这个二叉树创建出来就可以了,首先创建节点,当我们遍历到#时跳过它拿数组后面的数据,因为在二叉树中它表示的是NULL,所以没有必要存入二叉树,然后以中序遍历的顺序将二叉树的内容打印出来就可以了

#include <stdio.h>
#include <stdlib.h>

typedef struct BinaryTree
{
    int val;
    struct BinaryTree* left;
    struct BinaryTree* right;
}BT;

BT* creaTree(char* a, int* pi)
{
    if(a[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }

    BT* node = (BT*)malloc(sizeof(BT));
    node->val = a[(*pi)++];
    node->left = creaTree(a, pi);
    node->right = creaTree(a, pi);
    
    return node;
}

void Print(BT* root)
{
    if(root == NULL)
    {
        return;
    }

    Print(root->left);
    printf("%c ", root->val);
    Print(root->right);

}

int main() {
    char a[100] = {0};
    gets(a);
    int i = 0;
    BT* node = creaTree(a, &i);
    Print(node);
    return 0;
}

对称二叉树

这题我们可以判断该子树的左右子树是否相同,所以我们可以使用相同的树的代码,无非一个判断结构是否相同,一个判断是否对称,只需在递归时将它的左子树与右子树相比较就行了

bool check(struct TreeNode* q, struct TreeNode* p)
{
    if(q == NULL && p == NULL)
    return true;

    if(q == NULL || p == NULL)
    return false;

    if(q->val != p->val)
    return false;

    return check(q->left, p->right) && check(q->right, p->left);
}

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

平衡二叉树

先算出它左右节点的个数然后在相减,如果小于1就返回false,它的每个左右子树的深度都需要比较

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

    int Hleft = TreeHeight(root->left);
    int Hright = TreeHeight(root->right);

    return Hleft > Hright ? Hleft + 1 : Hright + 1; 
}

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

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

    if(abs(left - right) > 1)
    {
        return false;
    }

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

翻转二叉树

我们这里的思路是先翻转子树,然后翻转整个树

struct TreeNode* mirrorTree(struct TreeNode* root){
    if(root == NULL){
        return NULL;
    }

    struct TreeNode *left = mirrorTree(root -> left);
    struct TreeNode *right = mirrorTree(root -> right);
    root -> left = right;
    root -> right = left;
    return root;
}

方便理解,我这里画了递归展开图

递归展开图:

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值