二叉树的经典问题

一、单值二叉树

  如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。
只有给定的树是单值二叉树时,才返回 true;否则返回 false。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/univalued-binary-tree/

1.1思想

  先比较当前结点形成的子树,若当前结点有左孩子,再比较左孩子形成的子树;若当前结点有右孩子,最后再比较右孩子形成的子树。

1.2画图

单值二叉树

1.3代码

bool isUnivalTree(struct TreeNode* root){
    if(root == NULL)
        return true;
	
	//如果左孩子存在,则比较当前结点与左孩子是否相同,不相同则返回false
    if(root->left && root->left->val != root->val)
        return false;
    //如果右孩子存在,则比较当前结点与右孩子是否相同,不相同则返回false
    if(root->right && root->right->val != root->val)
        return false;

	//若两颗子树分别是单值二叉树,则返回true
    return isUnivalTree(root->left) && isUnivalTree(root->right);
}

二、相同二叉树

  给你两棵二叉树的根结点 p 和 q ,编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同,并且结点具有相同的值,则认为它们是相同的。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/same-tree/

2.1思想

  若两棵树的根结点都不为空,则先比较两棵树的根结点是否相同,再比较左子树,最后再比较右子树。(类似于先序遍历)

2.2画图

相同二叉树

2.3代码

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
	//两棵树都为空,则返回true
    if(p == NULL && q == NULL)
        return true;
	
	//有一棵树为空,则返回false
    if(p == NULL || q == NULL)
        return false;
	
	//根结点不相同,返回false;
    if(p->val != q->val)
        return false;
	
	//先递归左子树,判断两颗树的左子树是否相同
	//再递归右子树,判断两棵树的右子树是否相同
    return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}

三、二叉树的遍历(返回数组)

  给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/binary-tree-preorder-traversal/

3.1思想

  计算出树的大小,树的大小为数组的大小。先序遍历该树,若根结点为空,则返回;若根结点不为空,则将该结点存储到数组当中,先序遍历左子树,再遍历右子树。最后返回该数组。

3.2画图

二叉树的遍历(返回数组)

3.3代码

//树的大小
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;
    PreOrder(root->left,a,pi);
    PreOrder(root->right,a,pi);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
	//*returnSize为数组大小
    *returnSize = TreeSize(root);

	//动态开辟数组,将树的结点一一存进数组当中
    int* a = (int*)malloc((*returnSize)*sizeof(int));
    int i = 0;
    PreOrder(root,a,&i);

	//返回数组
    return a;
}

四、翻转二叉树

  给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/invert-binary-tree/

4.1思想

  如果根结点为空,说明是空树,则返回NULL。如果根结点不为空,则递归翻转左右子树,最后再交换左右子树返回根结点。

4.2画图

翻转二叉树

4.3代码

struct TreeNode* invertTree(struct TreeNode* root){
    if(root == NULL)
        return NULL;
	
	//分别递归翻转左右子树
    struct TreeNode* left = invertTree(root->left);
    struct TreeNode* right = invertTree(root->right);

	//交换左右子树
    root->left = right;
    root->right = left;

	//返回原树
    return root;
}

五、对称二叉树

  给你一个二叉树的根节点 root , 检查它是否轴对称。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/symmetric-tree/

5.1思想

  递归比较根结点的左子树和根结点的右子树是否为对称二叉树(类似于相同二叉树的解法)

5.2画图

对称二叉树

5.3代码

//判断两个树是否对称
bool _isSymmetric(struct TreeNode* root1,struct TreeNode* root2)
{
	//如果该树左子树的根结点与右子树的根结点都为空,则返回true
    if(root1 == NULL && root2 == NULL)
        return true;
    //如果该树根结点的左孩子为空或者右孩子为空,则返回false
    if(root1 == NULL || root2 == NULL)
        return false;
	//如果左子树的根结点与右子树的根结点不同,则返回false
    if(root1->val != root2->val)
        return false;
	//递归左子树的左子树与右子树的右子树是否对称
	//递归左子树的右子树与右子树的左子树是否对称
    return _isSymmetric(root1->left,root2->right) && _isSymmetric(root1->right,root2->left);
}

bool isSymmetric(struct TreeNode* root){
	//判断该树的左子树和右子树是否对称
    return _isSymmetric(root->left,root->right);
}

六、另一个树的子树

  给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和结点值的子树。如果存在,返回 true ;否则,返回 false 。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/subtree-of-another-tree/

6.1思想

  若大树为空,则返回false;先判断大树是否跟目标树相同,如果相同则返回true,否则分别比较大树的左子树和右子树。

6.2画图

另一颗树的子树

6.3代码

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
	//两棵树都为空,则返回true
    if(p == NULL && q == NULL)
        return true;
	
	//有一棵树为空,则返回false
    if(p == NULL || q == NULL)
        return false;
	
	//根结点不相同,返回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){
	//如果大树为空,则返回false
    if(root == NULL)
        return false;

	//如果大树与目标树相同,则返回true
    if(isSameTree(root,subRoot))
        return true;

	//大树的左子树或右子树与目标树相同,则返回true
    return isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
}

七、根据遍历序列构建二叉树

  编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
来源:牛客网
链接:
https://www.nowcoder.com/practice/4b91205483694f449f94c179883c1fef?tpId=60&&tqId=29483&rp=1&ru=/activity/oj&qru=/ta/tsing-kaoyan/question-ranking

7.1思想

  根据先序序列,先判断首字符是否为#,为#则返回NULL,然后对下一个字符进行判断。如果该字符不为空,则先创建一个树结点存储该字符,再使用余下的字符构建左子树,最后再使用余下的字符构建右子树。

7.2画图

根据遍历序列构建二叉树

7.3代码

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

//创建树结点
typedef struct TreeNode
{
    char ch;
    struct TreeNode* left;
    struct TreeNode* right;
}TreeNode;

//根据先序序列构建二叉树
TreeNode* PreOrderCreate(char* str,int* pi)
{
	//如果字符为#,则判断下一个字符,返回NULL
    if(str[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }

	//创建一个树结点存储非空字符作为根结点
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    newNode->ch = str[*pi];
    (*pi)++;
	
	//先序序列构建左子树
    newNode->left = PreOrderCreate(str,pi);
    //先序序列构建右子树
    newNode->right = PreOrderCreate(str,pi);

	//返回最终构建出的树
    return newNode;
}

//中序遍历
void InOrder(TreeNode* root)
{
    if(root == NULL)
        return;

    InOrder(root->left);
    printf("%c ",root->ch);
    InOrder(root->right);
}

int main() 
{
	//创建一个大小为101的字符数组存储先序序列
    char str[101];
    scanf("%s",str);

	//从下标0开始
    int i = 0;
    TreeNode* root = PreOrderCreate(str,&i);

	//中序遍历
    InOrder(root);

    return 0;
}

八、判断二叉树是否是平衡二叉树

  给定一个二叉树,判断它是否是高度平衡的二叉树。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/balanced-binary-tree/

8.1思想

  如果原树为空,则认为其是平衡二叉树,返回true;如果原树不为空,则比较左右子树高度差的绝对值是否大于1,如果大于1,则说明不是平衡二叉树,返回false,最后再分别递归左右子树是否平衡,如果两个都平衡则返回true,否则返回false。

8.2画图

平衡二叉树

8.3代码

//求树的高度
int TreeSize(struct TreeNode* root)
{
    if(root == NULL)
        return 0;

    int leftSize = TreeSize(root->left);
    int rightSize = TreeSize(root->right);

    return (leftSize > rightSize) ? leftSize + 1 : rightSize + 1;
}

//判断是否为平衡二叉树
bool isBalanced(struct TreeNode* root){
	//如果原树为空,则认为原树是平衡二叉树
    if(root == NULL)
        return true;

	//如果根结点的左右子树高度差的绝对值大于1,则不是平衡二叉树,返回false
    if(fabs(TreeSize(root->left) - TreeSize(root->right)) > 1)
        return false;
	
	//左右子树都平衡则返回true,否则返回false
    return isBalanced(root->left) && isBalanced(root->right);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值