【数据结构初阶第十七节】二叉树算法题

Hi!

必须有为成功付出代价的决心,然后想办法付出这个代价。云边有个稻草人-CSDN博客

目录

一、单值二叉树

二、相同的树

三、对称二叉树

四、另一棵树的子树

五、二叉树遍历

(1)前序遍历

(2)中序遍历

(3)后序遍历

六、二叉树的构建及遍历

七、二叉树选择题

[Relaxing Time------](#Relaxing Time——)

[------------------------------------------ 《 像极了 》 ------------------------------------------](#—————————————— 《 像极了 》 ——————————————)


正文开始------接受挑战!

一、单值二叉树

965. 单值二叉树 - 力扣(LeetCode)

【图解】

【思路】

就是从根节点开始不断遍历,先遍历左子树,遍历到一个节点的时候判断该节点的左节点是否和该结点的值相等,再判断该节点的右节点是否和该结点相等,就这样不断地递归,return,注意,我们使用递归一定要注意**递归结束的条件,本题递归结束的条件是root == NULL时结束。**下面是代码+注释,照着代码把递归过程顺一遍,用箭头来代表函数栈帧的创建与销毁就没那么抽象了。把上节学的递归搞熟悉之后理解本题的递归就不是大问题。下一题------

【代码】

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
typedef struct TreeNode TreeNode;
bool isUnivalTree(struct TreeNode* root) 
{
    //递归结束的条件(找递归结束的条件还是很重要的)
    if(root == NULL)
    {
        return true;//直接return,root == NULL不影响结果,直接返回
    }
    //先判断root的左节点是否和根节点值相同,这里是不相同直接return false(注意这里的用法)
    if(root->left && root->left->val != root->val)
    {
        return false;
    }
    //再判断右节点是否和根节点相同,和上面同样的道理
    if(root->right && root->right->val != root->val)
    {
        return false;
    }

    //紧接着递归,判断root->left和root->right,也就是root的左右子树
    return isUnivalTree(root->left) && isUnivalTree(root->right);
    
}

二、相同的树

100. 相同的树 - 力扣(LeetCode)

【图解】

【代码】

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
typedef struct TreeNode TreeNode; 
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
    //当两个节点都为NULL时,相等
    if(p == NULL && q == NULL)
    {
        return true;
    }
    //当两个节点其一为NULL,不相等
    if(p == NULL || q == NULL)
    {
        return false;
    }
    //两个节点都不为NULL,这时判断不相等才能说明问题
    if(p->val != q->val)
    {
        return false;//这是根节点不相同时
    }
    //注意这里是&&,必须左右节点都相等返回True时才可以判断相等
    return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);  
}

三、对称二叉树

101. 对称二叉树 - 力扣(LeetCode)

本题会借助上题的思路,看看自己能不能做出来

【图解】

【代码】

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
    //当两个节点都为NULL时,相等
    if(p == NULL && q == NULL)
    {
        return true;
    }
    //当两个节点其一为NULL,不相等
    if(p == NULL || q == NULL)
    {
        return false;
    }
    //两个节点都不为NULL,这时判断不相等才能说明问题
    if(p->val != q->val)
    {
        return false;//这是根节点不相同时
    }
    //这里判断节点是否相同,注意传参的内容
    return isSameTree(p->left,q->right) && isSameTree(p->right,q->left);  
}

bool isSymmetric(struct TreeNode* root) 
{
    //调用上面的判断树是否相等的函数,注意这里传的形参,返回判断树是否相同的结果true/false
    return isSameTree(root->left,root->right);
}

四、另一棵树的子树

572. 另一棵树的子树 - 力扣(LeetCode)

【图解】

【代码】

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
    //当两个节点都为NULL时,相等
    if(p == NULL && q == NULL)
    {
        return true;
    }
    //当两个节点其一为NULL,不相等
    if(p == NULL || q == NULL)
    {
        return false;
    }
    //两个节点都不为NULL,这时判断不相等才能说明问题
    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;
    }
    //再去递归root树的左子树,判断与subRoot是否相等
    return isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
}

五、二叉树遍历

(1)前序遍历

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

【图解】

【代码】

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
typedef struct TreeNode TreeNode;
int TreeSize(TreeNode* root)
{
    //总的节点个数 = 根节点1 + 左子树结点个数 + 右子树结点个数
    if(root == NULL)
    {
        return 0;
    }
    return 1 + TreeSize(root->left) + TreeSize(root->right);
}

void _preorderTraversal(TreeNode* root,int* arr,int* pi)
{
    //前序遍历 根 左 右
    if(root == NULL)
    {
        return;
    }
    arr[(*pi)++] = root->val;
    _preorderTraversal(root->left,arr,pi);
    _preorderTraversal(root->right,arr,pi);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize) {
    //我们要将树遍历的结果放到数组里面,所以我们要动态创建一个数组
    //1.获取树的结点的个数,为动态开辟数组内存空间做准备
    *returnSize = TreeSize(root);

    //2.动态开辟一块空间
    int* returnArr = (int*)malloc(sizeof(int)*(*returnSize));

    //3.前序遍历树并存入到数组里面
    int i = 0;
    _preorderTraversal(root,returnArr,&i);

    return returnArr;
}

(2)中序遍历

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

中序遍历和前序遍历对于这道题来说其实都是一样的,只是其中遍历的方式不一样,整体思路是一样的,后序遍历亦是如此,前面的前、中、后序遍历学得OK的话实现这两道就没有任何问题。

【代码】

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

typedef struct TreeNode TreeNode;
int TreeSize(TreeNode* root)
{
    //总的节点个数 = 根节点1 + 左子树结点个数 + 右子树结点个数
    if(root == NULL)
    {
        return 0;
    }
    return 1 + TreeSize(root->left) + TreeSize(root->right);
}

void _inorderTraversal(TreeNode* root,int* arr,int* pi)
{
    //中序遍历  左 根 右
    if(root == NULL)
    {
        return;
    }
    _inorderTraversal(root->left,arr,pi);
    arr[(*pi)++] = root->val;
    _inorderTraversal(root->right,arr,pi);
}

int* inorderTraversal(struct TreeNode* root, int* returnSize) {
    //我们要将树遍历的结果放到数组里面,所以我们要动态创建一个数组
    //1.获取树的结点的个数,为动态开辟数组内存空间做准备
    *returnSize = TreeSize(root);

    //2.动态开辟一块空间
    int* returnArr = (int*)malloc(sizeof(int)*(*returnSize));

    //3.前序遍历树并存入到数组里面
    int i = 0;
    _inorderTraversal(root,returnArr,&i);

    return returnArr;
}

(3)后序遍历

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

【代码】

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
typedef struct TreeNode TreeNode;
int TreeSize(TreeNode* root)
{
    //总的节点个数 = 根节点1 + 左子树结点个数 + 右子树结点个数
    if(root == NULL)
    {
        return 0;
    }
    return 1 + TreeSize(root->left) + TreeSize(root->right);
}

void _postorderTraversal(TreeNode* root,int* arr,int* pi)
{
    //中序遍历  左 根 右
    if(root == NULL)
    {
        return;
    }
    _postorderTraversal(root->left,arr,pi);
    _postorderTraversal(root->right,arr,pi);
    arr[(*pi)++] = root->val;
}

int* postorderTraversal(struct TreeNode* root, int* returnSize) {
    //我们要将树遍历的结果放到数组里面,所以我们要动态创建一个数组
    //1.获取树的结点的个数,为动态开辟数组内存空间做准备
    *returnSize = TreeSize(root);

    //2.动态开辟一块空间
    int* returnArr = (int*)malloc(sizeof(int)*(*returnSize));

    //3.前序遍历树并存入到数组里面
    int i = 0;
    _postorderTraversal(root,returnArr,&i);

    return returnArr;
}

六、二叉树的构建及遍历

二叉树遍历_牛客题霸_牛客网

其实这道题整体不是很难,代码里面用到的申请结点,中序遍历啥的我们前面都写过,就是思路的第二点难些需要我们自己写一个二叉树递归的创建。

这是牛客网上的题,所有的都要自己实现,头文件也要自己写。

【代码】

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

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

BTNode* buyNode(char x)
{
    BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
    newnode->data = x;
    newnode->left = newnode->right = NULL;
    return newnode;
}

BTNode* createTree(char* arr,int* pi)
{
    //递归结束的条件
    if(arr[(*pi)] == '#')
    {
        (*pi)++;
        return NULL;
    }
    BTNode* root = buyNode(arr[(*pi)++]);
    root->left = createTree(arr,pi);
    root->right = createTree(arr,pi);

    return root;
}

//中序遍历
void InOrder(BTNode* root)
{
    if(root == NULL)
    {
        return;
    }
    InOrder(root->left);
    printf("%c ",root->data);
    InOrder(root->right);
}

int main() 
{
    //1.读取用户的输入并存入到数组里面
   char arr[100]; 
   scanf("%s",arr);

   //2.根据前序遍历字符串创建二叉树
   int i = 0;
   BTNode* root = createTree(arr,&i);

    //3.中序遍历二叉树
    InOrder(root);

    return 0; 
}

好了,到这里OJ题就告一段落了,下面开展选择题------

七、二叉树选择题

我们要先学习二叉树的一个性质

(1)对任何⼀棵⼆叉树, 如果度为 0 其叶结点个数为 n 0 , 度为 2 的分⽀结点个数为 n 2 ,则有 n 0 = n 2 + 1

学完这个性质我们来练练选择题,我们先独立做一下,题目后面有答案+解析

【解析】

链式二叉树遍历选择题

【解析】

本篇关于链式二叉树的习题就结束了,课下要多思考多自己实现代码多实践!

别害怕,即使很难也要前进,只不过是速度慢一点,也总比原地踏步的好,你觉得难,别人自然也不会觉得简单,别人都能学,我们为什么要退缩呢?前面一节我学习二叉链里面的递归一开始也觉得挺难的,但是我们可以尝试把它当做一块硬骨头,虽然难,但是我们一点一点的啃,一点一点的攻破,多整体思考几次也就觉得没那么难了,甚至自己都会写了。既然选择了这条路我就要坚定地走下去!

依旧是认真地完成了本节课的博客,下节课学习排序。。。

完------


Relaxing Time------

跟你分享一首歌吧

------------------------------------------ 《 像极了 》 ------------------------------------------

像极了_永彬Ryan.B_高音质在线试听_像极了歌词|歌曲下载_酷狗音乐

至此结束------

我是云边有个稻草人

期待与你的下一次相遇。。。拜~~~

相关推荐
CodeJourney.1 分钟前
Deepseek助力思维导图与流程图制作:高效出图新选择
数据库·人工智能·算法
Liudef0617 分钟前
Stable Diffusion模型高清算法模型类详解
人工智能·算法·ai作画·stable diffusion
柠石榴1 小时前
【练习】【二叉树】力扣热题100 102. 二叉树的层序遍历
c++·算法·leetcode·二叉树
邴越1 小时前
Leetcode 112: 路径总和
算法·leetcode·职场和发展
2301_801037731 小时前
力扣-字符串
算法·leetcode·职场和发展
冠位观测者1 小时前
【Leetcode 每日一题】1328. 破坏回文串
数据结构·算法·leetcode
一只_程序媛1 小时前
【leetcode hot 100 53】最大子数组和
算法·leetcode·职场和发展
邴越1 小时前
Leetcode 57: 插入区间
算法·leetcode·职场和发展
天若有情6731 小时前
用 C++ 实现选择题答案随机生成器:从生活灵感走向代码实践
c++·算法·生活
dorabighead2 小时前
小哆啦解题记:螺旋矩阵
算法·矩阵·力扣·大话算法