• 【数据结构】二叉树基础OJ题


    前言

    通过上一篇关于二叉树的介绍,我们有了一定的了解,到了这个阶段,我们对递归的感受也更深了一步。至此,我们通过一些题目来练习

    此篇博客仅记录博主自己一些有关二叉树的基础OJ题,分享自己的做题过程,如有错误,还请指出。

    题目来源:牛客网和力扣

    话不多说,直接开始我们的主题👇

    单值二叉树

    image-20220816165306558

    简单来说,结点的值都要相同。那我们可以去判断当前结点的值和左孩子的值相不相同,再去判断当前结点的值和右孩子的值相不相同。只要出现不同,那我们直接返回错误。再去递归左右孩子,直到结束。

    bool isUnivalTree(struct TreeNode* root){
        if(root == NULL)
        {
            return true;
        }
        else if(root->left!=NULL&&root->val != (root->left)->val)
        {
            return false;
        }
        else if(root->right!=NULL&&root->val!=(root->right)->val)
        {
            return false;
        }
        return isUnivalTree(root->left)&&isUnivalTree(root->right);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    image-20220816170259271

    这里有一个比较容易错的地方:判断的时候除了要判断结点的值是否相等之外,左右孩子必须是存在的!

    相同的树

    image-20220816171413835

    两棵树分别去比较(都为空肯定相等,其中一个为空就不相等),根的值比较,对应的子树比较。还是采用递归解决

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    image-20220816172823677

    另一棵树的子树

    image-20220816173147187

    这是一个很有意思的题目,我们可以让原树中的每颗子树(包括原树)去和subRoot比较。怎么比较❓我们可以利用上面的题相同的树去的函数进行判断。让原树的每个子树去比较即可

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    image-20220816174148980

    二叉树的前序遍历

    image-20220816174430690

    这道题可不是简单的打印出前序遍历。我们需要把结果存放在开辟的数组中。我们可以通过算出结点的个数开辟对应的空间。再根据前序遍历把结果放到数组中:

    int TreeSize(struct TreeNode*root)
     {
         if(root==NULL)
         {
             return 0;
         }
         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 n = TreeSize(root);
        int*arr = (int*)malloc(sizeof(int)*n);
        int i = 0;
        PreOrder(root,arr,&i);
         *returnSize = n;
        return arr;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    image-20220816175058524

    趁热打铁

    二叉树的中序遍历

    image-20220816182021690

    一样的做法:

     int TreeSize(struct TreeNode*root)
     {
         if(root==NULL)
         {
             return 0;
         }
         return TreeSize(root->left)+TreeSize(root->right)+1;
     }
    
     void InOrder(int*arr,struct TreeNode*root,int*pi)
     {
         if(root==NULL)
         {
             return;
         }
        InOrder(arr,root->left,pi);
         arr[*pi] = root->val;
         (*pi)++;
         InOrder(arr,root->right,pi);
     }
    
    int* inorderTraversal(struct TreeNode* root, int* returnSize){
        int n = TreeSize(root);
        int*arr = (int*)malloc(sizeof(int)*n);
        int i = 0;
        InOrder(arr,root,&i);
        *returnSize = n;
        return arr;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    image-20220816182054491

    二叉树遍历

    image-20220816182221449

    题目要求很简单:给出前序遍历,让我们建立二叉树,最后进行中序遍历输出。

    我们得先了解怎么去建立,我们以上面的示例1为例子:

    image-20220816183204838

    代码实现:

    #include 
    #include 
    
    typedef char BTDataType;
    typedef struct BinarryTree
    {
        struct BinarryTree*left;
        struct BinarryTree*right;
        BTDataType data;
    }BTNode;
    
    BTNode* BinarryTreeCreate(BTDataType* str,int*pi)
    {
        if(str[*pi]=='#')
        {
            (*pi)++;
            return NULL;
        }
        BTNode*root = (BTNode*)malloc(sizeof(BTNode));
        if(NULL == root)
        {
            perror("malloc fail");
            exit(-1);
        }
        root->data = str[*pi];
        (*pi)++;
        root->left = BinarryTreeCreate(str,pi);
        root->right = BinarryTreeCreate(str,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[101];
        gets(str);
        int i = 0;
        BTNode*root = BinarryTreeCreate(str,&i);
        InOrder(root);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    image-20220816184754067

    平衡二叉树

    image-20220816195925457

    这道题我的思路是求出左子树的高度和右子树的高度,判断差值,大于1就直接返回false,然后再去递归左子树和右子树

    int TreeDepth(struct TreeNode*root)
    {
        if(root==NULL)
        {
            return 0;
        }
        int left = TreeDepth(root->left);
        int right = TreeDepth(root->right);
        return left>right?left+1:right+1;
    }
    bool isBalanced(struct TreeNode* root){
        if(root == NULL||(root->left==NULL)&&(root->right==NULL))
            return true;
        if(abs(TreeDepth(root->left)-TreeDepth(root->right))>1)
            return false;
        return isBalanced(root->left)&&isBalanced(root->right);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    image-20220816200159142

    对称二叉树

    image-20220816200356592

    如果是对称二叉树的话,那么左子树和右子树同时为空,左结点的左值会等于右结点的右值,左结点的右值会等于右结点的左值。我们可以采用递归的方式来完成这道题:

    bool judge(struct TreeNode* left,struct TreeNode* right){
        if(left == NULL && right == NULL)
            return true;
        if(left == NULL || right == NULL || left -> val != right -> val)
            return false;
        return judge(left -> left,right -> right) && judge(left -> right,right -> left);
    }
    
    bool isSymmetric(struct TreeNode* root){
        if(root == NULL)
            return true;
        return judge(root -> left,root ->right);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    翻转二叉树

    image-20220816232225736

    实际上就是左右子树进行交换即可:

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    image-20220816233126531


    结语

    通过这几道简单的题目,我们对于递归有了进一步的理解,同时加深了对二叉树的理解,如果觉得自己学有余力的情况之下,我们还可以去做更多的题目,当然,这里的二叉树知识是比较基础的,后面会更进一步的学习,这次就先到这里结束了

  • 相关阅读:
    QT(9.1)对话框与事件处理
    数学建模的初阶-快速上手
    数据库的一级、二级、三级封锁协议
    大模型,教培机构要过窄门
    ruby on rails 常用时间
    Day692.Tomcat如何隔离Web应用 -深入拆解 Tomcat & Jetty
    【Java面试】带你从面试官的角度深入剖析,什么是Java虚拟机为什么要使用?
    推荐几种可以直接翻译PDF英文文献的方法
    分享自研实现的多数据源(支持同DB不同表、跨DB表、内存数据、外部系统数据等)分页查询工具类实现原理及使用
    Zalando Postgres Operator 快速上手
  • 原文地址:https://blog.csdn.net/weixin_60478154/article/details/126376571