数据结构基础8:二叉树oj+层序遍历。

news2024/9/24 3:21:13

二叉树oj+层序遍历

  • 题目一:二叉树的销毁:
    • 方法一:前序遍历:
    • 方法二:后序遍历:
  • 题目二:二叉树查找值为x的节点
    • 方法一:
    • 方法二:
    • 方法三:
  • 题目三:层序遍历:
    • 方法一:
  • 题目四:相同的树:
    • 方法一:
  • 题目五:对称二叉树:
    • 方法一:
  • 题目五:另一颗树的子树:
    • 方法一:
  • 题目六:二叉树的前序遍历:
    • 方法一:
    • 拓展:
  • 题目七:翻转二叉树:
    • 方法一:

题目一:二叉树的销毁:

方法一:前序遍历:

1.前序遍历需要先销毁根节点:
2.在销毁节点之前需要保存左右节点:
3.通过保存的节点的地址再一次进入函数进行递归:
4.总结:相当于从上向下遍历:

//2.销毁:
 
//方法一:(先序的销毁)保存根节点的左右节点的地址销毁自己。
void BeforeTreeDestory(struct TreeNode* root)
{
	//1.根节点为空:
	if (root == NULL)
		return;

	//2.保存左右节点的根节点:
	struct TreeNode* left = root->left;
	struct TreeNode* right = root->right;
	free(root);

	//3.进入递归:
	BeforeTreeDestory(left);
	BeforeTreeDestory(right);
}

方法二:后序遍历:

1.左子树右子树根,左子树又有左子树右子树根。
2.到走到返回的时候,这个时候左和右的走完回来了就可以销毁当前树的根
3.总结:这是一个先到最然后再去从下到上的销毁。
4.好处:不需要像前序遍历去保存左右节点的地址再一次进入递归(在返回的时候就可以销毁节点)

//方法二:(后序遍历)先进入左右子树然后这是一种从下到上的销毁:
void EndTreeDestory(struct TreeNode* root)
{
	if (root = NULL)
		return;

	//进入左右子树回来才销毁:
	EndTreeDestory(root->left);
	EndTreeDestory(root->right);

	//销毁根节点:
	free(root);
}

题目二:二叉树查找值为x的节点

方法一:

1.使用先序遍历;
///
2.返回的条件:
1.根为空就返回说明没有找到:
2.找到值为x的节点返回节点的地址。
3.注意:数值不相同不需要返回说明还没有找到不需要返回:


3.返回的是节点的地址如果使用&& 和 || 逻辑运算符是不会返回地址的是只会返回0,1的这是需要注意的。
4.递归注意:因为我们需要返回节点的地址是需要从return一个节点之后从递归开辟的栈帧空间中带回来:

struct TreeNode* BinaryTreeFind(struct TreeNode* root, TreeNodeData x)
{
	//1.根节点为空:
	if (root == NULL)
		return NULL;
		
	//2.数值相同(找到值为X的节点不需要继续往下找了):
	//只有数值相同的根节点才会被返回回来:
	if (root->val == x)
		return root;

	//3.进入左右子树,这个数值到了非常深才可以被找到:
	struct TreeNode* tmp1 = BinaryTreeFind(root->left, x);
	if (tmp1 != NULL)
		return tmp1;
	struct TreeNode* tmp2 = BinaryTreeFind(root->right, x);
	if (tmp2 != NULL)
		return tmp2;
	//左右子树都没有找到的情况:
	return NULL;

}

方法二:

1.在方法一的基础上进行优化:
2.你会发现根据上面的两个判断:
1.如果根节点为空就返回NULL
2.如果数据相同就返回节点
3.如果这颗树没有数值相同的节点就返回NULL
总结:不需要对函数返回值进行判空处理直接让返回值作为判断条件是空就不会进入语句里面,如果不是空就一定是数值相等的节点的地址。返回地址就没有问题。

struct TreeNode* BinaryTreeFind(struct TreeNode* root, TreeNodeData x)
{
	//1.根节点为空:
	if (root == NULL)
		return NULL;
		
	//2.数值相同(找到值为X的节点不需要继续往下找了):
	//只有数值相同的根节点才会被返回回来:
	if (root->val == x)
		return root;

	//方法二:
	struct TreeNode* tmp = NULL;
	tmp = BinaryTreeFind(root->left, x);
	if (tmp)
		return tmp;
	tmp = BinaryTreeFind(root->right, x);
	if (tmp)
		return tmp;
	return NULL;
}

方法三:

1.如果左子树没有节点的话就直接返回右子树的函数返回值就可以:
2.右子树中无非只有两个情况:
1.有数据返回固定的节点地址:
2.找到底没有数据返回NULL
所以右子树的返回就不需要去判断:

struct TreeNode* BinaryTreeFind(struct TreeNode* root, TreeNodeData x)
{
	//1.根节点为空:
	if (root == NULL)
		return NULL;
		
	//2.数值相同(找到值为X的节点不需要继续往下找了):
	//只有数值相同的根节点才会被返回回来:
	if (root->val == x)
		return root;
		//方法三:
		struct TreeNode* tmp = NULL;
		tmp = BinaryTreeFind(root->left, x);
		if (tmp)
			return tmp;
	
		return BinaryTreeFind(root->right, x);
		//1.返回值需要接受,层层接受。
		//2.防止返回值为空。
		//3.或和与的运算符返回的值是0/1 地址丢失!
}

题目三:层序遍历:

方法一:

1.层序顾名思义就是一层一层的去遍历数据:
2.可以使用队列的数据结构保存数据:、
3.让根带左右子树
4.在根节点被pop之前top出节点并且访问数值去打印并且将左右子树的根节点入队列:
5.当队列为空说明二叉树的所有节点已经被层序遍历完全了:

//4.层序遍历: 队列存储:
void LevelOrder(struct TreeNode* root)
{
	assert(root != NULL);
	//初始化队列:
	Que pQ;
	QueueInit(&pQ);

	//入根节点:
	QueuePush(&pQ, root);

	while (!QueueEmpty(&pQ))
	{
		//获取堆头的数据
		QueueDatatype top = QueueFront(&pQ);
		//打印队头数据:
		if(top!=NULL)
			printf("%d ", top->val);

		//出去之前把孩子带进来(不需要递归的!!!)
		if(top->left!=NULL)
		QueuePush(&pQ, top->left);
		if(top->right!=NULL)
		QueuePush(&pQ, top->right);

		//pop数据:
		QueuePop(&pQ);
	}


	//销毁队列:
	QueueDestor(&pQ);

}

题目四:相同的树:

请添加图片描述
相同的树:题目链接

方法一:

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    
    //1.如果两个都是空节点说明相同
    if(p==NULL && q==NULL)
        return true;
    //2.经过1的判断p,q中至少有一个不是空是有数值的:
    //这样的情况如果进入一定是false。
    if(p==NULL || q==NULL)
        return false;
    
    //3.经过1,2的判断到这里一定满足两个节点都不是空节点。
    //两个情况:
    //1.两个节点的值不相同返回false
    //2.两个节点的值相同但是还没有找完所有的节点所以继续进入递归寻找:
    if(p->val != q->val)
        return false;

    //4.如果两个 左子树对应已经有不相同的了就不需要进入右树了:
    return isSameTree(p->left,q->left) 
    && isSameTree(p->right,q->right);
}

题目五:对称二叉树:

方法一:

1.这个题目和上面那个有一点点相似,这里比较一颗树的左右子树是否对称。上一个题目是比较直接给好的两个数的是否相同:
2.我们可以写一个子函数去传这一颗树的左右子树的根节点作为新的两颗树的根节点判断是否对称:
3.判断对称是判断相反的节点值是否相同(不同于判断俩颗树的相同相对位置的值是否相同)

请添加图片描述
对称二叉树:题目链接

bool isdouSymmetric(struct TreeNode* p ,struct TreeNode* q)
{
    //两个都为空,走到底了!
    if(p==NULL && q==NULL)
        return true;
    //一个空,一个不是空:
    if(p==NULL || q==NULL)
        return false;
    //两个都不是空:L
    if(p->val != q->val)
        return false;
    //第一个是判断左数的左和右树的右的对称:
    //第二个是判断左数的右和右树的左的对称
    return isdouSymmetric(p->left , q->right)
    &&isdouSymmetric( p->right ,q->left );
}


bool isSymmetric(struct TreeNode* root){
    //写一个子函数进入左右子树:
    return isdouSymmetric(root->left,root->right);
}

题目五:另一颗树的子树:

在这里插入图片描述
另一颗树的子树:题目链接

方法一:

1.有两个树一个树是父母。一颗树是儿子在父母中有可能找到儿子。
2.注意二子要和父母中的这个树完全相同直到后面都为空了不能说一部分相同后面还有一部分不相同的两个树:
3.我们前面写过判断两个数是否相同的函数现在找到父母这个数子树中的一个根和待比较树的根节点的相同就有可能存在相同的子树
4.当父母这个数到空就说明这颗子树没有相同的树包括没有数值的相等:
5.原函数使用 || 连接的好处是如果左树中有相同的子树并且返回了true就不需要再加入右树去判断,如果左树中没有相同的树还可以到右树中去寻找。只有左右都为false才返回false表示不存在相同的子树

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    //1.两个空数
    if(q==NULL && p==NULL)
    {
        return true;
    }
    //2.一个为空 另一个必须不为空:
    if(p==NULL || q==NULL)
    {
        return false;
    }
    //3.两个数值一开始就不相等:
    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){
    //1.没有子树返回false
    if(root==NULL)
        return false;

    //2.根节点的值相同有可能是相同子树的根节点:
    if(root->val == subRoot->val)
    {
        if(isSameTree(root,subRoot))
        {
            return true;
        }
    }

    //进入递归(先序遍历):
    return isSubtree(root->left , subRoot)
    || isSubtree(root->right , subRoot);
}

题目六:二叉树的前序遍历:

在这里插入图片描述
前序遍历:题目链接

方法一:

1.分析一下函数的参数和返回值:
1.返回一个数组的首地址(已经保存和前序遍历的数据)!
2.需要在堆区开辟空间这样才可以在外面找到这个数组的内容:
2.returnsize 返回数组的大小帮助外面去遍历数据:
3.使用计算节点个数的函数:

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

void Traversal(struct TreeNode* root , int* tmp , int* i)
{
    if(root==NULL)
        return;

    tmp[*i]=root->val;
    (*i)++;

    Traversal(root->left , tmp , i);
    Traversal(root->right, tmp , i);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize){
    //1.开辟数组,返回顺序表长度
    int n=TreeSize(root);
    *returnSize = n;

    int* tmp=(int*)malloc(sizeof(int)*n);
    //2.给顺序表中添加内容:

    int i=0;
    Traversal(root , tmp , &i);
    return tmp;
}

拓展:

中序遍历:题目链接
后序遍历:题目链接

题目七:翻转二叉树:

请添加图片描述
翻转二叉树:题目链接

方法一:

1.不需要考虑左右子树为空的情况.
2.直接进行交换,下一次递归进入函数如果为空就会返回用了下一次函数判断当前为空的处理!
3.翻转是翻转每一颗树左右子树的根节点的情况!

请添加图片描述

void convert(struct TreeNode* root)
{
    if(root==NULL)
        return;

    struct TreeNode* tmp=NULL;
    tmp=root->left;
    root->left=root->right;
    root->right=tmp;
    convert(root->left);
    convert(root->right);
}

struct TreeNode* invertTree(struct TreeNode* root){
    if(root==NULL)
        return root;
    
    convert(root);
    return root;
}

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

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

相关文章

全球与中国双壳鼻夹板市场:增长趋势、竞争格局与前景展望

双壳鼻夹板是一种医疗器械,用于鼻部手术后的支撑和稳定,以及减轻手术区域的肿胀和出血。它是由柔软的材料制成,通常是塑料或硅胶。双壳鼻夹板的设计呈现类似于两个壳体或半壳体,可以覆盖整个鼻部或其一侧。它的形状和大小可以根据…

网络基础-应用层协议-HTTP/HTTPS

HTTP/HTTPS HTTP基本概念协议格式请求报文请求方法请求资源地址协议版本 应答报文 常见Header常见状态码与状态描述Cookie&Sessionhttp协议特点 HTTPS基本概念对称加密与非对称加密数据摘要&数据指纹HTTPS工作过程探究只采用对称加密只采用非对称加密双方都采用非对称加…

酷开系统音乐频道,用音乐治愈你!

音乐作为娱乐生活中的一部分,它可以起到调节心情让身体放松的作用,同时还可以舒缓压力,给大脑一个休息的时间。有句话说得好:“耳机是人类的避难所,音乐是心脏的救命丸”。音乐是一种疗愈身心的存在,耳机线…

strncpy

strncpy: 函数介绍: 函数原型: char *strncpy(char *dest, const char *src, int n) 返回值:dest字符串起始地址 说明: 1、当src字符串长度小于n时,则拷贝完字符串后,剩余部分将用空字节填…

【PHP图片托管】CFimagehost搭建私人图床 - 无需数据库支持

文章目录 1.前言2. CFImagehost网站搭建2.1 CFImagehost下载和安装2.2 CFImagehost网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar临时数据隧道3.2 Cpolar稳定隧道(云端设置)3.3.Cpolar稳定隧道(本地设置) 4.公网访问测…

Bigemap在土地规划行业是怎么应用的?

选择Bigemap的原因: 获取途径:国土部门内部使用的是arcgis专用的系统,也安装不来arcgis软件,所以在网上找的我们软件软件上有影像地图,可以看高程海拔,有测量画图工具,可以导入和导出SHP和CAD文件&#xf…

远程ssh连接manjaro无法使用系统剪切板

文章目录 背景本机环境 vim的复制粘贴查看vim寄存器各种寄存器的含义 使用系统剪切板ssh访问系统剪切板安装配置X11再次查看vim寄存器 后记 背景 使用vim打开文件,把a文件中的内容,复制一部分到b文件中去。 大概步骤如下: 1、搜索要复制的…

SD系列——图像高清化算法方法

图像高清化算法方法 文章目录 图像高清化算法方法一、通过 Extras 选项卡执行放大算法二、通过 SD upscale 脚本增强细节三、txt2img 页面下的 Hires Fix四、扩展插件 Ultimate SD upscale ControlNet Tile参数调整单用 Ultimate SD Upscale小结 五、Tiled Diffusion & VA…

怎么把两首歌曲拼接在一起?

怎么把两首歌曲拼接在一起?音乐的美妙旋律能够陶冶人们的心灵,在日常生活和工作中,许多用户会使用各种歌曲来进行剪辑和制作。尤其在媒体行业工作的用户,每天都需要使用大量不同歌曲的片段,进行拼接和剪辑来进行视频制…

深入理解Linux网络笔记(一):内核是如何接收网络包的

本文为《深入理解Linux网络》学习笔记,使用的Linux源码版本是3.10,网卡驱动是Intel的igb网卡驱动 Linux源码在线阅读:https://elixir.bootlin.com/linux/v3.10/source 1、内核是如何接收网络包的 1)、Linux网络收包总览 在TCP/I…

数字IC验证23915--寄存器方法

文章目录 镜像值与期望值predication的分类自动预测显示预测 uvm_reg的访问方法寄存器健康检查![在这里插入图片描述](https://img-blog.csdnimg.cn/8b1832ab43854068970bb5a66d851d06.png) 镜像值与期望值 寄存器模型中的每一个寄存器,都应该有两个值,…

【计算机基础】Git系列2:配置多个SSH

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…

Python 07面向对象的三大特点【封装、继承、多态】

😀前言 在软件开发的过程中,面向对象编程(Object-Oriented Programming,简称 OOP)已经成为了一种不可或缺的编程范式。它允许开发人员创建属于自己的对象,具有其特征和行为,通过将数据和方法绑定…

Python中进行特征重要性分析的9个常用方法

特征重要性分析用于了解每个特征(变量或输入)对于做出预测的有用性或价值。目标是确定对模型输出影响最大的最重要的特征,它是机器学习中经常使用的一种方法。 为什么特征重要性分析很重要? 如果有一个包含数十个甚至数百个特征的数据集,每个特征都可能…

排序与分页——“MySQL数据库”

各位CSDN的uu们你们好呀,今天,小雅兰的内容是MySQL数据库里面的排序与分页,下面,让我们进入排序与分页的世界吧!!! 排序数据 分页 排序数据 排序规则 使用 ORDER BY 子句排序 ASC&#xf…

在JavaScript中,什么是浏览器事件循环(browser event loop)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 浏览器事件循环(Browser Event Loop)⭐ 执行同步任务⭐ 处理微任务队列(Microtask Queue)⭐ 处理宏任务队列(Macrotask Queue)⭐ 重复循环⭐ 写在最后 ⭐ 专栏简介 前…

一、K近邻算法K-NN

一、算法思路 K近邻算法,k-nearest neighbor,即K-NN 通俗来说:给定一个元素,然后以该元素坐标为圆心开始画圆,其中K值是超参数需要人为给定,圆的半径逐渐增大(距离度量采用欧氏距离),直到包含其…

【电子元件】常用电子元器件的识别之电容器

目录 前言1. 电容器的简介2.电容器的识别1. 铝电解电容器2.钽电解电容器3.固态电解电容器4.瓷介电容器5. 贴片陶瓷电容器6. 聚丙烯电容7. 金属化聚丙烯薄膜电容器8. 独石电容器9. 涤纶电容器10. 超小型金属化聚酯薄膜电容器11. 可变电容器11.1 空气可变电容器11.2 薄膜介质可变…

Vue前端页面打印

前端依赖10-插件"print-js": “^1.6.0” 一:简介 print-js 是一个 Vue.js 插件,用于在 Vue.js 项目中实现打印功能。它依赖于 print-js 库,所以需要安装这个库。 能实现以下功能: PDF打印(默认&#xff…

Python语言:求水仙花数案例讲解

求水仙花数是循环和判断语句相结合的一个经典案例。 思路分析 通过循环遍历100到999之间的数字然后根据他们的个位,十位,百位上的数字立方和是否为他本身来判断分析得出什么数是水仙花数。 1)如何循环遍历100到999的所有数字? 使…