入门二叉树-一起来递归【上】

本文详细讲解了从单值二叉树的判断、最大深度计算,到前序遍历、相同树比较和翻转二叉树的递归实现,适合初学者理解二叉树基本操作。

1. 单值二叉树

本题来源于leetcode 965. 单值二叉树

1.1 题目描述

image-20211126181527722

提示

image-20211126181541905

1.1.1 接口函数

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


bool isUnivalTree(struct TreeNode* root){

}

1.2 大致框架

1.2.1 思路与想法

二叉树的题目化为递归做,分析一颗树还是看它的rootleftchildrightchild,只要看

  1. 三个节点的值是否相等不相等,相等就继续往下走
  2. 在走的时候要保证return false的情况的条件,这个容易写错

1.2.2 具体步骤

  1. 我们之前说的要看三个节点相不相等怎么来进行判断?

    实际上只要证明leftchild==rootrightchild==root就可以证明这三个之间是不是互相都相等了,从而可以递归到更深层的子树都是相等的
    image-20211127153434993
    只要a=b=c,b=d=e,那么a=d=e,等号的传递性,也在于题目的特殊,所以可以解决起来很简单

  2. return false 的条件

如果只判断和root是否一样的话,是不够的,因为可能出现左孩子或这右孩子是空的,如果对空不排除的话,会算成返回false,因为NULL!=root->val,然而总要有空的情况出现,显然打不倒题目的要求,所以要加一个排空的条件

1.3 整体实现

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

image-20211127153005893

2.二叉树的最大深度

本题目来源于 104. 二叉树的最大深度

2.1 题目描述

image-20211126181803653

2.1.1 接口函数

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


int maxDepth(struct TreeNode* root){

}

2.2 大致框架

2.2.1 思路与想法

关键在于如何求一棵树的深度

分析书的模型可以想到一棵树的深度就是左子树和右子树的深度较大的那棵+1,由此又是递归产生了

image-20211126213716341

2.2.2 具体步骤

int maxDepth(struct TreeNode* root){
if(root==NULL)
{
    return 0;
}
return maxDepth(root->left)>maxDepth(root->right)?
maxDepth(root->left)+1:maxDepth(root->right)+1;
}

但是提示超出时间限制

一般倘若看上去是那么给了那么多组数据的话,超出了时间限制,说明题目这里堆时间复杂度给出了更高的要求

这里慢的原因是因为用三目操作符时相当于要return+1节点是,把左子树或者右子树深度又算了一遍,凭空增加了很多的时间,纯属浪费,所以这样不好,需要改进

只需要把求出来的值保存在变量里面就可以防止重复计算了

2.3 整体实现

int maxDepth(struct TreeNode* root){
if(root==NULL)
{
    return 0;
}
int leftDepth=maxDepth(root->left);
int rightDepth=maxDepth(root->right);
return leftDepth>rightDepth?leftDepth+1:rightDepth+1;
}

image-20211126222033838

补充:

还有一种方法可以解决

int maxDepth(struct TreeNode* root){
if(root==NULL)
{
    return 0;
}
return fmax(maxDepth(root->left),maxDepth(root->right))+1;
}

image-20211126222925179

fmax在这里没有重复调用,因为这里保存到形参里面去计算,没有重复计算

3.二叉树的前序遍历

本题目来源于leetcode 144. 二叉树的前序遍历

3.1 题目描述

image-20211127214412631

非递归的方法用c++会简单一点,之后学习c++后会使用c++实现

3.1.1 接口函数

/**
 * 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().
 */
int* preorderTraversal(struct TreeNode* root, int* returnSize){

}

3.2 大致框架

3.2.1 思路与想法

由于c语言的数组不想c++一样有vector,所以必须要malloc,但是malloc多少大小还是不清楚,所以为了避免增容问题,获取一下TreeSize,然后用_preorder实现前序遍历,最后通过返回值传给接口,解决问题,返回要求的值

3.2.2 具体步骤

先实现一下TreeSize

int TreeSize(struct TreeNode*root)
 {
     return root==NULL?0:TreeSize(root->left)+TreeSize(root->right)+1;
 }

正常走一遍前序遍历,放入数组

 void _preorder(struct TreeNode* root, int* arr ,int i)
 {
     if(root==NULL)
     return ;
     arr[i++]=root->val;
     _preorder(root->left,arr,i);
     _preorder(root->right,arr,i);
 }

最后把主函数完善好就可以了

但是出现了随机值

image-20211127222239805

其实原因还是形参的问题

_preorder(root->left,arr,i);

这样的一行传入的i是形参,形参只是一份临时拷贝,不能改变,所以i没有++,要改成传地址

 void _preorder(struct TreeNode* root, int* arr ,int pi)
 {
     if(root==NULL)
     return ;
     arr[(*pi)++]=root->val;
     _preorder(root->left,arr,pi);
     _preorder(root->right,arr,pi);
 }

3.3 整体实现

 int TreeSize(struct TreeNode*root)
 {
     return root==NULL?0:TreeSize(root->left)+TreeSize(root->right)+1;
 }
 void _preorder(struct TreeNode* root, int* arr ,int *pi)
 {
     if(root==NULL)
     return ;
     arr[(*pi)++]=root->val;
     _preorder(root->left,arr,pi);
     _preorder(root->right,arr,pi);
 }

int* preorderTraversal(struct TreeNode* root, int* returnSize){
    *returnSize=TreeSize(root);
    int *arr=(int*)malloc(sizeof(int)*(*returnSize));
int i=0;
_preorder(root,arr,&i);
return arr;
}

image-20211127223927351

4.相同的树

本题目来源于leetcode 100. 相同的树

4.1 题目描述

image-20211127224341638

4.1.1 接口函数

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


bool isSameTree(struct TreeNode* p, struct TreeNode* q){

}

4.2 大致框架

4.2.1 思路与想法

列多种情况排除

4.2.2 具体步骤

  1. 双空情况,true
  2. 一个空一个不空,false
  3. 值不一样,false
  4. 往子树走

4.3 整体实现

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

image-20211127223927351

5.翻转二叉树

本题目来自leetcode 226. 翻转二叉树

5.1 题目描述

image-20211128202357556

5.1.1 接口函数

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


struct TreeNode* invertTree(struct TreeNode* root){

}

5.2 大致框架

5.2.1 思路和想法

由于要求的输出的左右子树的位置跟输入正好是相反的,我们可以递归的交换左右子树来完成这道题。

时间复杂度: O(n)
空间复杂度: O(h)

5.2.2 具体步骤

  • 终止条件:当前节点为 NULL 时返回
  • 递归条件:交换当前节点的左右节点,再递归的交换当前节点的左节点,递归的交换当前节点的右节点
  • 利用tmp实现交换

5.3 整体实现

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

image-20211129080311215

觉得有所收获的话给个一键三连哦,谢谢

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

言之命至9012

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值