二叉树OJ练习

📣:大部分关于二叉树的OJ题都涉及分治与递归思想,同时这些也是二叉树的基础,接下来的一些OJ题将这些思想运用的淋漓尽致,相信你看完以后对这种思想也理解的更加深刻同时也能进一步的掌握二叉树的结构。

目录

1、单值二叉树

2、检查两棵树是否相同 

3、对称二叉树

4、翻转二叉树 

5、二叉树的前序遍历 

6、二叉树的中序遍历  

7、二叉树的后续遍历  

8、另一棵树的子树 

9、二叉树的构建和遍历 


1、单值二叉树

🎯原题链接:力扣

🤔思路: 

所谓单值二叉树就是树的结点的数据都相同,也就是说只要每个根和其左右孩子都相等,那么此二叉树必定为单值二叉树,同时根结点也是别的结点的孩子结点,孩子结点也会成为根结点,我们利用递归+分治思想来进行判断。

📝代码如下: 

bool isUnivalTree(BTNode* root)
{
	if (root == NULL)
	{
		return true;  //如果为空树,同样符合单值,返回true
	}

	if (root->left && root->left->val != root->val)
	{
		return false; //如果左孩子存在且左孩子的值与根结点不同,返回false
	}
	if (root->right && root->right->val != root->val)
	{
		return false; //如果右孩子存在且右孩子的值与根结点不同,返回false
	}

	return isUnivalTree(root->left) && isUnivalTree(root->right);  //递归分治转换为子问题
}

2、检查两棵树是否相同 

🎯原题链接:https://leetcode.cn/problems/same-tree/

 🤔思路: 

两棵树相同其数值和结构都必须保持相同。首先我们先排除特殊情况,如果两棵树的结点都为空,那么符合题意。如果比较过程中任何一个先为空就不符合题意,然后我们再继续比较结点的值是否相等。

📝代码如下: 

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、对称二叉树

🎯原题链接:力扣

🤔思路: 

检查一棵树是否对称我们首先可以将树分为左右两个部分,此时我们写一个辅助函数用来判断对称结点的值是否相等。

📝代码如下: 

//辅助函数比较对称的值是否相等
bool _isSymmetric(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 _isSymmetric(p->left,q->right)&&_isSymmetric(p->right,q->left);
}

bool isSymmetric(struct TreeNode* root){
    //树为空也符合对称
    if(root==NULL)
    {
        return true;
    }

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

 4、翻转二叉树 

🎯原题链接:力扣

🤔思路: 

从上图中我们可以看到翻转二叉树就是将每层的根结点的左右子树进行交换,我们可以额外写一个子函数专门进行结点交换。假设我们从根结点开始使根结点的左右子树进行交换,这样我们就解决了第一二层的翻转,接下来我们利用递归将根结点的左子树传过去作为根结点交换左右子树,把根结点的右子树传过去作为新的根结点交换左右子树,以此类推直到翻转完毕。

📝代码如下: 

//辅助函数,进行结点的交换
void SwapNode(struct TreeNode*root)
{
    struct TreeNode*tmp=root->left;
    root->left=root->right;
    root->right=tmp;
}

struct TreeNode* invertTree(struct TreeNode* root){
    if(root==NULL)
    {
        return NULL;
    }
    SwapNode(root);
    invertTree(root->left);
    invertTree(root->right);
    
    return root;

}

 5、二叉树的前序遍历 

🎯原题链接:力扣

 🤔思路:

前序遍历我们在上篇博文中已经讲过,而这道题也就完美的运用了上一节的知识。题目中表述我们要动态开辟一块数组用来存放数据,那么我们首先要知道的就是树的结点的个数有多少个,知道了结点个数我们也就知道了所要开辟的空间的大小。此时我们可以创建辅助函数TreeSize来计算结点个数。开辟完数组接下来就是和之前讲过的前序遍历顺序一样,先把根结点放入数组里面,再递归加分治,为了避免每次递归都要malloc,我们可以再创建一个子函数专门进行递归。

⚠:此题函数参数还有一个*returnSize,也就是我们要把数组元素个数返回给调用者。

📝代码如下: 

//求二叉树结点个数
 int TreeSize(struct TreeNode*root)
 {
     return root==NULL?0:TreeSize(root->left)+TreeSize(root->right)+1;
 }

 //辅助函数专门用来递归,防止用主函数递归每次都要malloc
 void _preorder(struct TreeNode*root,int *a,int*i)
 {
     if(root==NULL)
     return ;
     a[(*i)++]=root->val;
     _preorder(root->left,a,i);
     _preorder(root->right,a,i);
 }
int* preorderTraversal(struct TreeNode* root, int* returnSize){
    //计算结点个数
    int size=TreeSize(root);
    //开辟数组
    int *a=(int *)malloc(sizeof(int)*size);
    int i=0;
    _preorder(root,a,&i);
    *returnSize=i;
    return a;
}

6、二叉树的中序遍历  

🎯原题链接:力扣

 🤔思路:

和前序遍历思路一样,这里不再多赘述。

📝代码如下: 

//计算二叉树结点个数
 int TreeSize(struct TreeNode*root)
 {
     return root==NULL?0:TreeSize(root->left)+TreeSize(root->right)+1;
 }

 //辅助函数专门用来递归,防止用主函数递归每次都要malloc
 void InOrder(struct TreeNode*root,int*a,int*i)
 {
     if(root==NULL)
     return ;
     InOrder(root->left,a,i);
     a[(*i)++]=root->val;
     InOrder(root->right,a,i);
 }

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

 7、二叉树的后续遍历  

🎯原题链接:力扣

 🤔思路:

和前序遍历思路一样,这里不再多赘述。

📝代码如下: 

//计算二叉树结点个数
 int TreeSize(struct TreeNode*root)
 {
     return root==NULL?0:TreeSize(root->left)+TreeSize(root->right)+1;
 }

 //辅助函数专门用来递归,防止用主函数递归每次都要malloc
 void PosOrder(struct TreeNode*root,int*a,int*i)
 {
     if(root==NULL)
     return ;
     PosOrder(root->left,a,i);
     PosOrder(root->right,a,i);
     a[(*i)++]=root->val;
 }

int* posorderTraversal(struct TreeNode* root, int* returnSize){
    int size=TreeSize(root);
    int*a=(int*)malloc(sizeof(int)*size);
    int i=0;
    PosOrder(root,a,&i);
    *returnSize=i;
    return a;
}

8、另一棵树的子树 

🎯原题链接:力扣

 🤔思路:

遍历root树的每一个结点,同时作为子树的根,跟subRoot比较,我们可以用上面写过的函数isSameTree用来比较两棵树是否相同,符合条件则返回true。

📝代码如下:

//判断两棵树是否相同
bool isSameTree(struct TreeNode*root,struct TreeNode*subRoot)
{
    if(root==NULL&&subRoot==NULL)
    {
        return true;
    }
    if(root==NULL||subRoot==NULL)
    {
        return false;
    }
    if(root->val!=subRoot->val)
    {
        return false;
    }
    return isSameTree(root->left,subRoot->left)&&isSameTree(root->right,subRoot->right);
}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
    if(root==NULL)
    {
        return false; //根为空没有子树,直接返回false
    }
    if(isSameTree(root,subRoot))
    {
        return true;  //是子树就返回true
    }
    return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);

}

9、二叉树的构建和遍历 

🎯原题链接:二叉树遍历_牛客题霸_牛客网

 🤔思路:

题目要求将我们输入的字符串根据先序遍历(前序遍历)构建成树,然后再根据中序遍历方式将树打印,下面我们以测试用例为主讲解一下大致过程。

构建树:

首先遇到a,不是#,继续往下构建a的左子树b,再往下构建b的左子树c,再递归回溯构建c的左子树#,此时c的左子树为空,构建c的右子树为#也为空,递归回溯构建b的右子树d,继续构建d的左子树e,构建e的左子树#为空,递归回溯构建e的右子树g,再构建g的左右子树均为空,递归回溯构建d的右子树f,构建f的左右子树均为空,递归回溯构建a的右子树#为空,构建结束。

中序遍历打印:

构建好树的结构后我们按照中序遍历的顺序打印出来即可。

📝代码如下:

#include <stdio.h>

//创建二叉树结构
typedef struct BinaryTreeNode
{
    char data;
    struct BinaryTreeNode*left;
    struct BinaryTreeNode*right;
}BTNode;

//创建树
BTNode*CreateTree(char*a,int*pi)
{
    if(a[*pi]=='#')
    {
        (*pi)++;
        return NULL;
    }
    
    BTNode*root=(BTNode*)malloc(sizeof(BTNode));
    root->data=a[(*pi)++];
    
    root->left=CreateTree(a,pi);
    root->right=CreateTree(a,pi);
    return root;
}
//打印树
void InOrder(BTNode*root)
{
    if(root==NULL)
        return ;
    InOrder(root->left);
    printf("%c ",root->data);
    InOrder(root->right);
}

int main()
{
    char a[100];
    scanf("%s",a);
    int i=0;
    BTNode*tree=CreateTree(a,&i);
    InOrder(tree);
    return 0;
}
  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值