二叉树——经典练习题

目录

前言:

一、单值二叉树

        题目描述:

        思路分析:

        代码实现:

二、二叉树最大深度 

        题目描述:

        思路分析:

                代码实现: 

三、检查两颗树是否相同

        题目描述:

        思路分析: 

        代码实现:

四、另一颗树的子树

        题目描述:

        思路分析: 

        代码实现: 

五、二叉树的前序遍历

        题目描述:

        思路分析:

        代码实现:

六、二叉树的构建及遍历

        题目描述:

        思路分析: 

        代码实现:

最后:


前言:

        通过前面的学习,我们已经学习了二叉树的基础知识,以及二叉树功能的实现。我们学习讲究的是:知行合一。那我们一起来检验一下我们的学习成果吧!

一、单值二叉树

        题目描述:

如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。

只有给定的树是单值二叉树时,才返回 true;否则返回 false

        思路分析:

                单值二叉树就是二叉树每个节点的值都相同,这时,我们有两种思路去实现:

                方法一:再构造一个函数,把根节点的值传过去和左节点和右节点进行比较,如果相同,这个没啥意义,应用不同来判断,如果不同就返回假,为真就继续递归。

                方法二:用根节点和其左右节点进行比较,思路与上文类似。

                本题采用方法二。

        代码实现:

bool isUnivalTree(struct TreeNode* root) {if(root == NULL){return true;}if(root->left && root->val != root->left->val || root->right && root->right->val != root->val){return false;}return isUnivalTree(root->left) && isUnivalTree(root->right);
}

                以下是递归展开图,大致展示了函数调用过程,帮助大家理解:

                题目链接:. - 力扣(LeetCode) 

二、二叉树最大深度 

        题目描述:

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

        思路分析:

                此题一看不是和之前讲解的高度一样吗?对于我之前的说明不以为然的读者,可能会写出以下代码:

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

                这段代码运行的大逻辑是没错的,但是会有效率问题,测试用例通过是没啥问题的,但要是要求时间复杂度了,就危险了。

                可以看出,超出了时间限制,这时我们就要对其进行优化,具体过程上一篇文章已经分析过了,优化方法为:加一个记录的变量即可,便可减少复杂度。

                代码实现: 

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

                题目链接:. - 力扣(LeetCode)

三、检查两颗树是否相同

        题目描述:

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

        思路分析: 

                本题要求判断两颗树是否相同,那么,这么说明两颗树相同呢?无外乎就是一一比较,根与根比较,左子树与左子树比较,右子树与右子树比较,就这么简单。但,我们还要考虑的情况是:如果为空,这么判断,分两种情况:一、都为空:那就返回true。二、一个为空,另一个不为空。该放回false。以上便是所有情况。

        代码实现:

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

        题目链接:. - 力扣(LeetCode)

四、另一颗树的子树

        题目描述:

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

        思路分析: 

                本题一看没啥思路,这咋搞,很难办对吧。这时,突然想到,能不能放到数组里,然后看小数组是不是大数组的子集。但是,画图分析一下又好像不行。

                唯一的思路断了,这该怎么办?在思索之时,你突然想到:专业的事交给专业的人去干。这道题可不可以分解为这两步:第一步:先找到所有父节点。第二步:在经行判断两棵树是否相同。对于第二步和上题有异曲同工之妙,简单优化即可。

                第一步应该怎么办?很简单,直接把节点扔进去就行了,交给第二步去判断就行了,直到找到符合的节点。

                所以,这道题看起来很复杂,其实也不简单,对吧。

        代码实现: 

bool istree(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 istree(root->left,subRoot->left) && istree(root->right , subRoot->right);
}bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){if(root == NULL){return false;}if(root->val == subRoot->val && istree(root,subRoot)){return true;}return isSubtree(root->left,subRoot) || isSubtree(root->right , subRoot);//找父节点
}

        题目链接:. - 力扣(LeetCode)

五、二叉树的前序遍历

        题目描述:

        给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

        思路分析:

                二叉树的前序遍历,这不是说过吗?那好,给大家这个接口,看一看能否在leetcode官方上能不能运行通过。

int* preorderTraversal(struct TreeNode* root, int* returnSize) {}

                对于以上接口这里解释一下返回值这个问题。一个函数不是只有一个,那咱们应该返回啥,对于该问题,我们要先明白传过来的都代表什么意思。

                咱们首先明白,只要实现接口里的大逻辑即可,输入和打印咱们是不必实现的。打印是有leetcode官方写的代码实现的,你要实现打印肯定要知道这个树的的大小对吧。所以,那个returnsize是用来记录大小的。那为什么不用常量呢?因为:形参是实参的一份临时拷贝。要改变形参要传地址,地址需要用指针来接收。

                说了这么多,如果读者能够实现,就不用看博主的讲解,如果不行,就一件三连跟着博主继续走即可。

                对于我们现在来说,求一个树的节点个数是很简单的一件事,就不在赘述。知道了节点数,便可动态开辟一个数组用来存放数据。那么,我们接下来的难点为:如何把二叉树中的元素放到数组中。

                这件事也很简单,就是用前序遍历,把打印换成放元素仅此而已。

        代码实现:

int preTraversal(struct TreeNode* root) {if (root == NULL) {return 0;}return preTraversal(root->left) + preTraversal(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 = preTraversal(root);int* a = (int*)malloc(sizeof(int) * (*returnSize));int i = 0;preorder(root, a, &i);return a;
}

        题目链接:. - 力扣(LeetCode)

六、二叉树的构建及遍历

        题目描述:

描述

编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

输入描述:

输入包括1行字符串,长度不超过100。

输出描述:

可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。 每个输出结果占一行。

         

        思路分析: 

                本题要求我们实现一个二叉树,并用中序遍历的方式将其打印出来。这道题很有难度,但有了前面的代码,在此时难度也不是很大了。本题的数据从外部输入,我们还要将其打印。所以,我们要自己实现接受外部的输入和用中序的方式对外打印,这部分代码难度不大,中序打印的类似实现已经讲过,不在赘述。

                本题讲解的难点为:构建二叉树。从以上的输入示例中,我们看到有‘#’这样的符号,但打印没它,那,我们可不可以写出以下代码:

if(a[(*pi)++] == '#'){return NULL;}

                乍一看没啥问题。但仔细想想问题就来了:这个的意思是我每次判断pi都加一,你觉得可行还是不可行。很显然,这不可行。所以,我们要把pi的++放入到{}内才能更好的符合我们的意图。我们放入字符采用的是先序遍历,这部分大家都能掌握,只不过,我们不清楚整颗二叉树的大小,所以,我们每次构建前都要用malloc开辟一下。

        代码实现:

#include <stdio.h>
#include<stdlib.h>
typedef char BTDataType;typedef struct BinaryTreeNode {BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
} BTNode;
BTNode* BTCreatTree(char* a,int* pi)
{if(a[*pi] == '#'){(*pi)++;return NULL;}BTNode* root = (BTNode*)malloc(sizeof(BTNode));root->data = a[(*pi)++];root->left = BTCreatTree(a,pi);root->right = BTCreatTree(a,pi);return root;
}
void BTNodePrint(BTNode* root)
{if(root == NULL){return;}BTNodePrint(root->left);printf("%c ",root->data);BTNodePrint(root->right);
}
int main() {char a[101];scanf("%s",a);int i = 0;BTNode* ret = BTCreatTree(a,&i);BTNodePrint(ret);return 0;
}

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

最后:

        二叉树的学习,我们目前就告一段落了,后续的进阶内容会在c++部分讲解。今天讲解的题目中最后三道难度较大,还望各位读者在学习完后能够多多练习,这样才能够掌握。如在学习中,有啥问题可在评论区交流,也可私信。期待与读者再会。

完!

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

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

相关文章

mac电脑用n切换node版本

一、安装 node版本管理工具 “n” sudo npm install -g n二、检查安装成功&#xff1a; n --version三、查看依赖包的所有版本号 比如: npm view webpack versions --json npm view 依赖包名 versions --json四、安装你需要的版本的node sudo n <node版本号> // 例如…

【C语言项目实战】使用单链表实现通讯录

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 期待您的关注 ​ 目录 一、引言 二、单链表的基本概念 三、通讯录项目的需求分析 四、通讯录的数据结构 五、通讯录的接口 1.通讯录初始化 / 导入外部…

2010-2024年别克维修手册和电路图线路接线图资料更新

经过整理&#xff0c;2010-2024年别克汽车全系列已经更新至汽修帮手资料库内&#xff0c;覆盖市面上99%车型&#xff0c;包括维修手册、电路图、新车特征、车身钣金维修数据、全车拆装、扭力、发动机大修、发动机正时、保养、电路图、针脚定义、模块传感器、保险丝盒图解对照表…

Qt 界面上控件自适应窗体大小 - 随窗体缩放

Qt 界面上控件自适应窗体大小 - 随窗体缩放 引言一、在Qt Designer上设置二、参数详解三、参考链接 引言 添加布局&#xff0c;设置控件的minimumSize、maximumSize和sizePolicy可以使其跟随窗体进行自适应缩放 - 如上图所示。 一、在Qt Designer上设置 在代码中设置效果一致…

HTML.

HTML:超文本标记语言&#xff08;Hyper Text Markup Language&#xff09; 超文本&#xff1a;不同于普通文本&#xff0c;可以定义图片&#xff0c;音频&#xff0c;视频等内容 标记语言&#xff1a;由标签构成的语言 HTML标签都是预定义好的HTML代码直接在浏览器中运行&#…

JVM之【运行时数据区】

JVM简图 运行时数据区简图 一、程序计数器&#xff08;Program Counter Register&#xff09; 1.程序计数器是什么&#xff1f; 程序计数器是JVM内存模型中的一部分&#xff0c;它可以看作是一个指针&#xff0c;指向当前线程所执行的字节码指令的地址。每个线程在执行过程中…

深度神经网络——什么是生成式人工智能?

1.引言 生成式人工智能最近引起了很大的关注。 该术语用于指依赖无监督或半监督学习算法来创建新的数字图像、视频、音频和文本的任何类型的人工智能系统。 麻省理工学院表示&#xff0c;生成式人工智能是过去十年人工智能领域最有前途的进展之一。 通过生成式人工智能&#…

AI智能体|手把手教你使用扣子Coze图像流的文生图功能

大家好&#xff0c;我是无界生长。 AI智能体&#xff5c;手把手教你使用扣子Coze图像流的文生图功能本文详细介绍了Coze平台的\x26quot;图像流\x26quot;功能中的\x26quot;文生图\x26quot;节点&#xff0c;包括创建图像流、编排文生图节点、节点参数配置&#xff0c;并通过案例…

Layui设置table表格中时间的显示格式

1、问题概述? 【数据库中的时间格式】 【Layui中table表格默认的显示格式】 默认的格式中会显示时间的毫秒单位,但是这个毫秒有时候是不需要的。 总结:这个时候我们就需要定义table表格中的时间显示格式。 2、解决办法? 【解决后时间的显示格式】 【解决办法1:通过字符…

Linux基础 (九):Linux 进程复制与替换

各位看官&#xff0c;本篇博客干货满满&#xff0c;请耐下心来&#xff0c;慢慢吸收&#xff01;哈哈哈&#xff0c;内功一定会大增&#xff01; 目录 一、printf 函数输出问题 1.1 第1个示例代码 1.2 第2个示例代码 1.3 分析与结论 二、主函数参数介绍 三、复制进程 fo…

Android 处理音频焦点,解决音乐播放冲突的问题

1. 音频焦点是什么 在Android中&#xff0c;两个或多个 Android 应用可以同时将音频播放到同一输出流&#xff0c;系统会将所有音频混合在一起。 但是多数情况下&#xff0c;这对于用户来说是感到困惑的。为了避免多个应用的多个音频一起播放&#xff0c;Android 引入了“音频…

【百度智能体】零代码创建你的 AI 宠物助手

前言 今天给大家介绍一下百度的 AI 产品 – 百度智能体&#xff0c;在文心智能体平台你可以0代码就可以创建出属于自己的 AI 机器人&#xff0c;几乎可以选择任何你想要的领域或者行业机器人&#xff0c;进行无代码打造自己的对话助手&#xff0c;本文将介绍文心智能体&#x…

jmeter之MD5加密接口请求教程

前言&#xff1a; 有时候在项目中&#xff0c;需要使用MD5加密的方法才可以登录&#xff0c;或者在某一个接口中遇到 登录获取token后才可以进行关联&#xff0c;下面介绍下遇到的常见使用 一、第一种方法&#xff1a;使用jmeter自带的函数助手digest 选择工具&#xff0c;选择…

高效的大型语言模型适应方法:提升基础性的解决方案

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

表查询基础【mysql】【表内容 增,删,改,查询】

博客主页&#xff1a;花果山~程序猿-CSDN博客 文章分栏&#xff1a;Linux_花果山~程序猿的博客-CSDN博客MySQL之旅_花果山~程序猿的博客-CSDN博客Linux_花果山~程序猿的博客-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我…

Redis(十三) 事务

文章目录 前言事务的特性Redis事务的执行原理Redis中使用事务WATCH UNWATCH实现乐观锁 前言 前面我们学习 MySQL 的时候&#xff0c;肯定也学习了事务。事务是什么&#xff1f;给大家举个例子&#xff1a;假如我给朋友微信转账&#xff0c;我给他转了 100 块钱&#xff0c;当我…

Golang | Leetcode Golang题解之第114题二叉树展开为链表

题目&#xff1a; 题解&#xff1a; func flatten(root *TreeNode) {curr : rootfor curr ! nil {if curr.Left ! nil {next : curr.Leftpredecessor : nextfor predecessor.Right ! nil {predecessor predecessor.Right}predecessor.Right curr.Rightcurr.Left, curr.Righ…

Vue3实战笔记(46)—Vue 3高效开发定制化Dashboard的权威手册

文章目录 前言Dashboard开发总结 前言 后台管理系统中的Dashboard是一种图形化的信息显示工具&#xff0c;通常用于提供一个特定领域或系统的概况。它可以帮助用户监控和分析数据&#xff0c;快速获取重要信息。可以帮助用户监控业务状况、分析数据、获取关键信息和管理资源。…

list的模拟实现(一)

嗨喽大家好&#xff0c;时隔许久阿鑫又给大家带来了新的博客&#xff0c;list的模拟实现&#xff08;一&#xff09;&#xff0c;下面让我们开始今天的学习吧&#xff01; list的模拟实现&#xff08;一&#xff09; 1.list splice接口的使用 2.list尾插的实现 3.list的迭代…

Python编程的黑暗魔法:模块与包的神秘力量!

哈喽&#xff0c;我是阿佑&#xff0c;今天给大家讲讲模块与包~ 文章目录 1. 引言1.1 模块化编程的意义1.2 Python中模块与包的概念概述 2. 背景介绍2.1 Python模块系统模块的定义与作用Python标准库简介 2.2 包的结构与目的包的定义与目录结构包在项目组织中的重要性 3. 创建与…