二叉树经典例题

news2025/2/1 18:04:08

前言:

本文主要讲解了关于二叉树的简单经典的例题。

因为二叉树的特性,所以关于二叉树的大部分题目,需要利用分治的思想去递归解决问题。

分治思想:

把大问题化简成小问题(根节点、左子树、右子树),返回条件就是最小规模的子问题

一、二叉树中结点的个数

思路:

采用分而治之的思想, 先访问左子树,再访问右子树,然后再加上自己的个数也就是1。

原码:

//采用分治的思想去解决
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
	/*if (root == NULL)
		return 0;
	else
	{
		return TreeSize(root->left) + TreeSize(root->right) + 1;
	}*/
}

二、二叉树中叶子结点的个数

思路:

分为三个判断条件。

  1. 如果是空结点,就返回0
  2. 如果是叶子结点就返回1
  3. 不满足上述两种情况,就继续访问左子树+右子树 

原码:

int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	if (root->left == NULL && root->right == NULL)
		return 1;
	return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

三、求第k层的结点个数

思路:

当前树的第k层 = 左子树的k-1层 + 右子树的k-1层,以此类推

当k == 1时,如果不为空结点,就返回1,如果是空结点就返回0。

原码:

int TreeKLevel(BTNode* root, int k)
{
	assert(k > 0);
	if (root == NULL)
		return 0;
	if (k == 1)
	{
		return 1;
	}
	return TreeKLevel(root->left, k - 1)
		+ TreeKLevel(root->right, k - 1);
}

四、判断单值二叉树

965. 单值二叉树

思路:

首先明确等号具有传递性,只要根节点和右节点相等,然后根节点与左结点相等,就说明这颗小树就是单值。

并且这是前序遍历,先遍历根节点,如果根节点不是单值二叉树,那么就没有必要去遍历后面的。

这点可以利用&&与操作符实现,与操作符的特性是只要前者是假,后面就不会执行

原码:

bool isUnivalTree(struct TreeNode* root){
    //采用前序的思想
    //利用等于号的传递性
    if(root == NULL)
        return true;
    //跟左节点比较    
    if(root->left)
    {
        if(root->val != root->left->val)
            return false;
    }
    //跟右结点比较
    if(root->right)
    {
        if(root->val != root->right->val)
            return false;
    }
    return isUnivalTree(root->left) && isUnivalTree(root->right);
}

五、销毁二叉树

思路:

采用后序遍历,防止先销毁根节点,导致左右节点找不到了

原码:

void DestroryTree(BTNode* root)
{
	//递归必须要有判断条件
	if (root == NULL)
		return;
	//需要后序遍历,不然先销毁根节点,左右子树就找不到了
	DestroryTree(root->left);
	DestroryTree(root->right);
	free(root);
	root = NULL;

六、在二叉树中根据值搜索结点

思路:

可以直接采取前序遍历,

  1. 最小子问题就是当结点为空时返回空
  2. 结点的值就是寻找的值就返回该节点
  3. 不满足上述条件,就继续递归遍历,先左子树再右子树,如果左子树已经找到结点,直接返回

原码:

BTNode* TreeFind(BTNode* root, int x)
{
	if (root == NULL)
		return NULL;
	if (root->val == x)
		return root;
	BTNode* ret = TreeFind(root->left, x);
	if (ret != NULL)
		return ret;
	return TreeFind(root->right, x);
}

七、检查两颗树是否相同

100. 相同的树

思路:

采用分治的思想,把问题逐步缩小,最小子问题就是两个结点是否相同

  1. 我们首先要清楚是不是空树
  2. 然后如果一个为空,另一个不为空
  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);
}

八、对称二叉树

​​​​​​101. 对称二叉树

思路;

本题跟上一题两颗二叉树是否相同非常相似,只需要将比较的结点改变顺序,因为是对称,所以左节点要跟右节点相等。

原码:

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->right) && isSameTree(p->right,q->left);
}

bool isSymmetric(struct TreeNode* root){
    return isSameTree(root->left,root->right);
}

九、另一棵树的子树

572. 另一棵树的子树

思路:

这道题也是判断相同树的衍生题目,当根节点与subTree的根节点相同时,可以判断两颗树是否相同,并利用||来判断。

原码:

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
    //防止递归到空结点,造成非法访问
    if(root == NULL)
        return false;
    //相同前提是根节点要一致
    if(root->val == subRoot->val)
    {
        if(isSameTree(root,subRoot))
            return true;
    }
    //只要发现相同,没有必要进行下面的比较,所以是||
    return isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
}

十、二叉树的最大深度

104. 二叉树的最大深度

思路:

我们分别求出左子树和右子树的深度,再返回较大的值。

注意:

我们不能将代码写成上面的形式,首先定位上面的代码是非常差的代码,返回值返回的时候会重新进入函数计算,并且是每一个结点!因此我们需要提前将返回值保存起来,将值进行比较去返回。

原码:

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

十一、二叉树的前序遍历

​​​​​​144. 二叉树的前序遍历

思路:

本题并不是简单的递归求解,需要根据题目要求,因为我们用C语言进行求解。

  1. 数组的大小需要我们先自己求这颗树的结点大小,单独开辟一个函数去求解
  2. 我们不能递归自己的函数,因为每次递归都需要动态开辟一个新的数组,因此还需要重新创建一个函数去解决
  3. 注意新的函数中数组下标i的值需要传地址,因为递归过程中有很多i,直接传地址

原码:

//先提前算好二叉树结点的个数,便于开辟动态数组的大小
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;
    (*i)++;
    preorder(root->left,arr,i);
    preorder(root->right,arr,i);
}

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

十二、通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树

注意:

*pi++  (*pi)++两者含义不同,为了避免优先级的问题,我们直接加上括号!

原码:

BTNode* BinaryTreeCreate(char* str, int* pi)
{
	if (str[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = (BTNode*)malloc(sizeof(BTNode) * 1);
	root->val = str[*pi];
	(*pi)++;
	root->left = BinaryTreeCreate(str, pi);
	root->right = BinaryTreeCreate(str, pi);
	return root;
}

十三、二叉树的层序遍历

涉及到层序遍历,大部分情况下需要借助队列进行求解。

思路:

上一层带下一层,先进先出。

原码:

十四、判断是否是完全二叉树

思路:

利用层序遍历,如果非空结点是连续的,就是完全二叉树。

如果非空结点是不连续的,中间有空结点,就是非完全二叉树。

原码:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1061265.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】STL详解(十)—— 用红黑树封装map和set

​ ​📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:C学习 🎯长路漫漫浩浩,万事皆有期待 上一篇博客:【C】STL…

国庆中秋特辑(八)Spring Boot项目如何使用JPA

目录 一、Spring Boot 项目使用 JPA 的步骤二、Spring Boot 项目使用 JPA 注意事项三、Spring Boot 项目使用 JPA 常用语法 Spring Boot项目如何使用JPA,具体如下 一、Spring Boot 项目使用 JPA 的步骤 添加依赖 在项目的 pom.xml 文件中添加 Spring Boot JPA 和数…

如何使用 ChatGPT 创建强大的讲故事广告

shadow: 使用AI技术来辅助创作故事越来越流行,从事营销相关工作的人员需要不断适应和学习新的技术和工具,以应对行业的变化和挑战。 如何使用ChatGPT创建讲故事的广告: A. 确定品牌故事和信息传递B. 确定目标受众C. 开发概念D. 使…

【LeetCode热题100】--153.寻找旋转排序数组中的最小值

153.寻找旋转排序数组中的最小值 由于该排序数组经由1到n次旋转,所以旋转后的数组折线图为: 最小值处于中间,同时对于最后一个元素x:在最小值右侧的元素,它们的值一定严格小于x,而在最小值左侧的元素,它们的…

因为在此系统上禁止运行脚本

问题: 解决办法: vue项目搭建中"因为在此系统上禁止运行脚本"报错,解决方法 - 你的剧本 - 博客园 (cnblogs.com)

文举论金:黄金原油全面走势分析策略独家指导

市场没有绝对,涨跌没有定势,所以,对市场行情的涨跌平衡判断就是你的制胜法宝。欲望!有句意大利谚语:让金钱成为我们忠心耿耿的仆人,否则,它就会成为一个专横跋扈的主人。空头,多头都…

10.2 调试事件获取DLL装载

理解了如何通过调试事件输出当前进程中寄存器信息,那么实现加载DLL模块也会变得很容易实现,加载DLL模块主要使用LOAD_DLL_DEBUG_EVENT这个通知事件,该事件可检测进程加载的模块信息,一旦有新模块被加载或装入那么则会触发一个通知…

大数据Doris(四):直接编译(CentOS/Ubuntu)准备

文章目录 直接编译(CentOS/Ubuntu)准备 一、环境准备

国庆与中秋两节合一的长假

国庆节是我国最重要的节日之一,而中秋节则是一个家庭团聚和感恩的时刻,当这两个重要的节日同时降临,就为人们带来了双重的欢庆。今年(2023)的国庆节与中秋节难得地重合在一起,让人们享受了长达8天的假期。这…

一文看懂功率MOSFET FCP190N60 N沟道 基础知识

什么是MOSFET的原意是:MOS(Metal Oxide Semiconductor金属氧化物半导体),FET(Field Effect Transistor场效应晶体管),即以金属层(M)的栅极隔着氧化层(O&#…

实验室超声波萃取技术的原理和特点是什么?

梵英超声(fanyingsonic)实验室超声波清洗机 超声波萃取中药材的优越性源于超声波的特殊物理性质。通过压电换能器产生的快速机械振动波,超声波可减少目标萃取物与样品基体之间的作用力,从而实现固液萃取分离。 (1)加速介质质点运…

13个最强大的摄影测量软件【2023最新】

如果你曾经使用 Google 地球探索过外国城市或玩过《堡垒之夜》,就会体验到摄影测量的好处。 通过将多张航空照片以及来自 NASA 的海拔和地形信息相结合,Google 地球可以创建大多数主要城市的逼真 3D 视图。 视频游戏制造商 Epic Games 使用摄影测量技术…

苹果V3签名是什么?优势是什么?什么场合需要应用到?该怎么部署?

v3签名,或称为Apple Developer Program v3签名,是苹果公司在2021年6月推出的一种签名格式,用于对应用程序进行签名和验证。 它是取代了之前的v2签名格式,用于增强应用程序的安全性和完整性。 v3签名能够做到以下几点:…

[硬件基础]-快速了解PWM

快速了解PWM 文章目录 快速了解PWM1、什么是PWM2、PWM的频率3、PWM的占空比4、PWM信号的输出电压计算5、脉宽调制幅度6、脉冲宽度调制生成技术6.1 使用微控制器生成脉冲宽度调制6.2 使用模拟电路产生脉冲宽度调制6.3 其他产生PWM的方法 在本文中,将介绍脉宽调制。 脉…

QT基础入门——信号和槽机制(二)

前言: 在Qt中,有一种回调技术的替代方法:那就是信号和槽机制。当特定事件发生时,会发出一个信号。Qt的小部件中有许多预定义的信号,但我们可以将小部件子类化,向它们添加自定义的信号。槽是响应特定信号的…

静电监控系统的作用在哪

静电监控系统主要用于监测和管理静电的产生、传导和消除,以防止静电对生产过程和环境的损害。具体来说,静电监控系统的作用包括以下几个方面: 监测静电的产生和传导:静电监控系统可以实时监测生产现场的静电产生和传导情况&#…

【LeetCode热题100】--33.搜索旋转排序数组

33.搜索旋转排序数组 对于有序数组,使用二分查找: 该题只保证了部分有序,也能进行二分查找 在常规二分查找时查看当前mid分割出来的两部分[l,mid]和[mid1,r],哪个部分是有序的,根据有序的那个部分确定我们该如何改变…

解决WPF+Avalonia在openKylin系统下默认字体问题

一、openKylin简介 openKylin(开放麒麟) 社区是在开源、自愿、平等和协作的基础上,由基础软硬件企业、非营利性组织、社团组织、高等院校、科研机构和个人开发者共同创立的一个开源社区,致力于通过开源、开放的社区合作&#xff…

k8s集群-6(daemonset job cronjob控制器)

Daemonset 一个节点部署一个节点 当有节点DaemonSet 确保全部 (或者某些) 节点上运行一个 Pod 的副本。加入集群时,也会为他们新增一个 Pod 。当有节点从集群移除时,这些Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。 DaemonSet 的典型用…

Integrity Plus for Mac,保障网站链接无忧之选

在如今数字化的时代,网站链接的完整性对于用户体验和搜索引擎排名至关重要。如果您是一位网站管理员或者经常需要检查网站链接的人,那么Integrity Plus for Mac(Integrity Plus)将成为您最好的伙伴。 Integrity Plus是一款专业的…