二叉树的遍历及相关衍生

二叉树的遍历及相关衍生

  • 前言
  • 二叉树的遍历
    • 建树
    • 二叉树的遍历
      • 遍历的分类
      • 代码部分
  • 遍历根的应用
    • 打印树中的每个数据
      • 代码部分
    • 遍历计算树节点个数
      • 代码部分
    • 计算二叉树的深度
      • 思路
      • 代码部分
    • 第k层个数
  • 结束

前言

如标题所示,在这里我们要研究的是二叉树的遍历。

为什么不讲二叉树的增删查改?
在实际使用过程中,二叉树的增删查改没有多大作用,二叉树是作为一种数据结构,不是用来存储数据,更多的是用来进行搜索

赫赫有名的红黑树和B树,都是其的限制优化的产物之一。

但是身为小白的博主现在只能先从最基本的遍历开始玩起。

博主刚学C++一点,为了练习和熟悉,所以用的是C++,但是也没多熟练,还是有C的老习惯,请各位多多海涵

二叉树的遍历

建树

我们想要学习对树的遍历,首先就要有一颗树。

所以我们先要进行一次快速的建树
在这里插入图片描述
我们要建立这样一颗树

可以看出我们在设计类的变量时,需要设置三个
1:存储数据的int
2:存放右子节点的指针
3:存放左子节点的指针

class tree
{
public:
	tree* inittree(int x, tree* left, tree* right)
	{
		tree* ptr = (tree*)malloc(sizeof(tree));
		assert(ptr);
		ptr->_data = x;
		ptr->_left = left;
		ptr->_right = right;
		return ptr;
	}
private:
	int _data;
	tree* _left;
	tree* _right;
};
int main()
{
	tree t1;
	tree* ptr3=t1.inittree(3, nullptr, nullptr);
	tree* ptr2=t1.inittree(2, ptr3, nullptr);
	tree* ptr6 = t1.inittree(6, nullptr, nullptr);
	tree* ptr5 = t1.inittree(5, nullptr, nullptr);
	tree* ptr4 = t1.inittree(4, ptr5, ptr6);
	tree* ptr1 = t1.inittree(1, ptr2, ptr4);
}

没错,建树就是这么简单直接,因为我们主要来学习他的遍历,所以建树这些繁琐的事情快速解决就好了。

二叉树的遍历

看名字,所谓遍历,就是将二叉树中的数据全部访问一遍

在这里插入图片描述
如果我们要实现这颗二叉树的遍历,想必大家都多少听过,二叉树和递归算法脱不了一点关系。

虽然有些人听到递归就有点小怕,但是如果把思路理解了以后,递归可比迭代快太多了。

当我们进行遍历的时候,有这样三种操作

1:访问根,就是遍历的历,对根存储的数据进行访问。
2:走向左子树,
3:走向右子树
在这里插入图片描述
设计的都是先访问左子树,再访问右子树
这应该是约定俗成的把,虽然先右到左也没什么区别,但是从左往右还是看着赏心悦目一点。

所以纠结的只有根的访问顺序,这样就牵扯到遍历的差别了。

遍历的分类

前根遍历
顾名思义,就是先根后左右
先根后左右
这里我们先将
1:访问根
2:访问左子树
3:访问右子树
这样设定好
在这里插入图片描述
在这里插入图片描述
因为递归是对函数的重复调用,作用对象是每一个节点,所以到了左子树的节点后,要对子节点进行同样与根节点的操作
即先访问节点数据,在进行左子树和右子树的访问。
在这里插入图片描述
这里为了方便看清,就在第一个第二个第三个节点加了前缀,1.1就是第一个节点访问根。

这里当第三个节点访问左右子树为空后,直接进行返回。

剩下两个遍历类型为

中根遍历

即先访问左子树,访问根,再访问右子树

后根遍历

即先访问左右子树,再访问根。

就不多讲了。

代码部分

void Traversaltree(tree* root)
	{
		if (root == nullptr)
		{
			cout << " NULL";
			return;
		}
		//访问根的部分按照遍历存放
		//访问根的代码按照具体情况而定

//访问根放这-前根
		printtree(root->_left);
//访问根放这-中根
		printtree(root->_right);
//访问根放这-后根
	}

遍历根的应用

打印树中的每个数据

由于我们这个二叉树不是完全二叉树这种特殊树,所以用数组打印时,就会导致残缺不堪
在这里插入图片描述
就比如打印这颗树

代码部分

void printtree(tree* root)
	{
		if (root == nullptr)
		{
			cout << " NULL";
			return;
		}
		//前根遍历打印
		cout << " " << root->_data; 
		printtree(root->_left);
		printtree(root->_right);
	}

遍历计算树节点个数

代码部分

	int  sizetree(tree* root)
	{
		if (root == nullptr)
			return 0;
		return sizetree(root->_left)
		 + sizetree(root->_right) + 1;

	}

按照代码画图

在这里插入图片描述
先是通过sizetree(root->_left),从根节点不断访问左子树,然后节点继续访问它的左子树,直到节点的左子树为空。
当访问到3节点时,在进行左子树为NULL后返回0

随后执行sizetree(root->_right),对3节点的右子树进行访问,为空,返0。

执行return sizetree(root->_left) + sizetree(root->_right) + 1;
返回 {(左子树的返回)0+(右子树的返回)0 + 1=1}

这个时候重新返回了2节点,
在这里插入图片描述

对于二节点,收到了左子树的返回1,右子树为空,返回0

返回给1节点的访问左子树的返回值为
(2节点访问左子树返回值) 1+(2节点访问左子树返回值) 0 +1=2

解释到这,就可以推测出整个递归运行的逻辑了。

计算二叉树的深度

故名思义,就是计算二叉树的深度。

为了更能体现作用,所以将之前的树重新接了一下
在这里插入图片描述

思路

这里我们采用直接思考解决方法,直接写代码
不通过想象它的一次一次递归的执行方式去写代码
这样更加快速,当然等会还是会解释递归的执行思路的。

这里我们先不看整个二叉树,我们先来看,对于单一的一个子节点来说
当它接收到来自左边和右边的深度后
将右边和左边的深度进行比较
如果左边较大,则返回左边深度+1值
如果右边较大,则返回右边深度+1值

为什么要+1?
因为返回深度的话还要把自己的深度+1

这样我们就可以试着写出一个代码了

if (root == nullptr)
     return 0;
return heighttree(root->_left) > 
heighttree(root->_right)
?
 heighttree(root->_left) + 1 
:
 heighttree(root->_right) + 1;

这样运行一下,发现还真可以计算,但是如果你深度进行观察这个代码,就会发现这个写法太挫了
当我们进行比较后,不停进行右子树和左子树访问后

在进行三目操作符执行后,居然还要进行左子树和右子树的访问,这样时间复杂度直接从On变到了On^2

其实要解决这个问题也很简单,加个计数的就好,接下来的是最优的代码。

代码部分

int heighttree(tree* root)
	{
		if (root == nullptr)
			return 0;
		int left=heighttree(root->_left);
		int right=heighttree(root->_right);
		return left > right ? left + 1 : right + 1;	
	}

在这里插入图片描述

首先不断执行int left=heighttree(root->_left);

不停访问左子树,到节点3时,左子树为空
赋值int left=0,之后执行int right=heighttree(root->_right);

访问到6节点,再执行6的左子树访问,到5节点

5节点左右为空,left right皆为0
进行三目操作符比较后,执行return right+1

此时回到6节点
6节点的左子树访问返回,进行赋值int left=1
右子树为空,所以int right=0
进行三目操作符比较后,执行return left+1

返回到 3节点
得到int right=2
left=0进行比较,返回right+1

…………
解释了两个三个节点操作过程就可以看出整个的递归逻辑了。

第k层个数

顾名思义,给定一个k,求第k层有几个节点

这里直接上代码了,因为难度和前面大差不差

//第k层个数
	int treeklevel(tree* root,int k)
	{
		if (root == nullptr)
			return 0;
		if (k == 1)
			return 1;
		return treeklevel(root->_left,k-1) 
		+ treeklevel(root->_right,k-1);
	}

结束

本人画图和解释的精力和能力有限,可能讲的也不是很清楚,正好又碰上递归这个难题,所以请各位多多海涵

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

郑哲:学习、应用初探与探索创新 | 提升之路系列(四)

导读 为了发挥清华大学多学科优势&#xff0c;搭建跨学科交叉融合平台&#xff0c;创新跨学科交叉培养模式&#xff0c;培养具有大数据思维和应用创新的“π”型人才&#xff0c;由清华大学研究生院、清华大学大数据研究中心及相关院系共同设计组织的“清华大学大数据能力提升项…

ros2 foxy创建一个包和节点-ubuntu20.04

文章目录 创建工作区目录创建包和节点colcon build编译CMakeLists.txt文件find_packageadd_executable package.xml面相过程的方式生命一个节点以面向对象的方式创建一个节点 创建工作区目录 mkdir -p ~/ros2_ws/src cd ~/ros2_ws我们创建了两个目录&#xff0c;ros2_ws和在他…

【电商必学】 WhatsApp 全新攻略:什么是交互式消息模板

网购与WhatsApp等社交通讯平台有着密不可分的关系&#xff0c;为什么这么说呢&#xff1f;因为基本上所有的网购的平台都会提供查询、下单方式给客户&#xff0c;而WhatsApp是全世界使用率最高的通讯平台&#xff0c;所以大部分电子商户都会选择WhatsApp Business与电子商务连接…

Linux pthread线程操作 和 线程同步与互斥操作

在Linux系统中玩线程&#xff0c;使用pthread&#xff0c;这篇博客记录如何创建线程和使用线程和线程的同步与互斥。 还有一份nginx线程池的代码供大家阅读学习&#xff01; 目录 一、简介 什么是线程 线程的优点、缺点 线程的应用场合 二、线程的使用 1. 创建线程 - p…

高并发场景下JVM调优实践

一、背景 2021年2月&#xff0c;收到反馈&#xff0c;视频APP某核心接口高峰期响应慢&#xff0c;影响用户体验。 通过监控发现&#xff0c;接口响应慢主要是P99耗时高引起的&#xff0c;怀疑与该服务的GC有关&#xff0c;该服务典型的一个实例GC表现如下图&#xff1a; 可以…

最值得学的编程语言是哪个?

如果让我推荐的话&#xff0c;我肯定首选是python啦&#xff01; 编程语言是一个计算机的概念&#xff0c;在我们有了计算机以后&#xff0c;想让它帮助我们做事情&#xff0c;就要通过计算机语言和它进行对话、交互&#xff0c;计算机语言能够被计算机所执行&#xff0c;完成…

【MFAC】基于全格式动态线性化的无模型自适应控制(Matlab代码)

例题来源&#xff1a;侯忠生教授的《无模型自适应控制&#xff1a;理论与应用》&#xff08;2013年科学出版社&#xff09;。 &#x1f449;对应书本 4.4 单输入单输出系统(SISO)全格式动态线性化(FFDL)的无模型自适应控制(MFAC) 上两篇博客分别介绍了基于紧格式和偏格式动态线…

Linux命令集(Linux常用命令--cat指令篇)

Linux命令集&#xff08;Linux常用命令--cat指令篇&#xff09; Linux常用命令集&#xff08;cat指令篇&#xff09;4.cat(concatenate)1. 查看文件内容&#xff1a;2. 连接多个文件&#xff1a;3. 创建文件并通过终端写入内容4. 输出内容编号 Linux常用命令集&#xff08;cat指…

【英语】大学英语CET考试,写作部分(论述文+应用文,6篇范文)

文章目录 3项评分标准&#xff08;内容&结构&#xff0c;语言&#xff09;0.1 论述文个人小结 1、论述文&#xff1a;审题与功能句2、论述文&#xff1a;修饰内容和名言模板3、论述文&#xff1a;现象作文&利弊分析4、论述文&#xff1a;给出权威论据和有侧重的现象5、…

在amd64与arm上用paddlelite部署paddelOCR(Ascend硬件)

由于部署的硬件是华为昇腾 NPU&#xff08;Ascend310&#xff09;&#xff0c;参考网址https://www.paddlepaddle.org.cn/lite/v2.10/demo_guides/huawei_ascend_npu.html#npu-paddle-lite 先拉取paddlelite用来编译库 git clone https://github.com/PaddlePaddle/Paddle-Lit…

反转字符串——leetcode344、leetcode541

文章目录 简单反转字符串题目详情分析Java完整代码 反转链表进阶问题题目详情分析Java完整代码 简单反转字符串 题目详情 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须…

RMAN-03009、ORA-19566数据文件坏块报错处理方法

在备份数据库的时候&#xff0c;出现RMAN-03009、ORA-19566报错&#xff1a; RMAN-03009: backup 命令 (c3 通道上, 在 04/29/2023 10:58:11 上) 失败 ORA-19566: 超出损坏块限制 0 (文件 E:\APP\ADMINISTRATOR\ORADATA\JHSEMR\JHEMR2.DBF) 继续执行其他作业步骤, 将不重新运行…

Github创建一个新仓库,关联本地数据并上传文件的图文步骤

工作中&#xff0c;我们经常会使用github来承享别人的代码果实&#xff0c;同时我们也会把自己的成果分享给别人&#xff0c;互相帮助。 今天的这篇图文教程非常重要&#xff0c;目标是使用Github来创建一个远程仓库&#xff0c;并和本地仓库对接&#xff0c;同时要做上传新内容…

区域医疗云his系统源码,具有可扩展、易共享、易协同的优势

云HIS系统采用SaaS软件应用服务模式&#xff0c;提供软件应用服务多租户机制&#xff0c;实现一中心部署多机构使用。相对传统HIS单机构应用模式&#xff0c;它可灵活应对区域医疗、医疗集团、医联体、连锁诊所、单体医院等应用场景&#xff0c;并提升区域内应用的标准化与规范…

python处理图像的各种技术镜像、旋转、遮挡、叠加、条带化

2.6 图像镜面对称 1、将图像水平镜面转换。 2、将图像垂直镜面转换。 import random #导入模块 import numpy as np import matplotlib.pyplot as plt a plt.imread("1.jpg") # 将图像沿着水平方向重复三次。 ba.copy() da.copy() # 将图像水平镜面转换。&…

LeCun、田渊栋参与撰写,70页「自监督学习」大全

来源 | 机器之心 微信号&#xff1a;almosthuman2014 「关于自监督学习&#xff0c;你想知道但又不敢问的一切都在这里了。」图灵奖得主、Meta 人工智能首席科学家 Yann LeCun 刚刚发了这样一则推文。 在推文中&#xff0c;LeCun 介绍了他和 Meta 人工智能研究院研究员、研究经…

javaEE初阶 — 服务器版本的表白墙案例

文章目录 原来版本涉及的问题设计程序1 点击提交2 页面加载 实现后端代码1 新建一个 Maven 项目。2 按照之前第一个 Servlet 程序的步骤来进行设置3 新建一个 MessageServlet 类 实现前端代码1 点击提交的时给服务器发送一个 POST 请求2 在页面加载时发送一个 GET 请求3 将数据…

【2023 年第十三届 MathorCup 高校数学建模挑战赛】C 题 电商物流网络包裹应急调运与结构优化问题 赛后总结之31页论文及代码

相关信息 &#xff08;1&#xff09;建模思路 【2023 年第十三届 MathorCup 高校数学建模挑战赛】A 题 量子计算机在信用评分卡组合优化中的应用 详细建模过程解析及代码实现 【2023 年第十三届 MathorCup 高校数学建模挑战赛】 B 题 城市轨道交通列车时刻表优化问题 详细建…

2.3 定点乘法运算

学习目标&#xff1a; 如果我要学习定点乘法运算&#xff0c;我会按照以下步骤进行学习&#xff1a; 确定学习目标&#xff1a;明确学习定点乘法运算的目的和重点&#xff0c;以便有针对性地进行学习。 掌握基础知识&#xff1a;首先需要了解定点数和定点乘法的基础知识&…

PySide2 QWebEngine与Web js交互

文章目录 单向交互双向传值案例 单向交互 QWebEngineView加载web页面&#xff0c;web页面中点击按钮&#xff0c;执行js代码&#xff0c;js的返回值传给QWebEnginePage&#xff0c;使用python进行保存结果。 单向&#xff0c;js向python(PySide2)端传输数据。 前端实现 <…