二叉树的遍历及相关衍生

news2024/11/28 15:22:43

二叉树的遍历及相关衍生

  • 前言
  • 二叉树的遍历
    • 建树
    • 二叉树的遍历
      • 遍历的分类
      • 代码部分
  • 遍历根的应用
    • 打印树中的每个数据
      • 代码部分
    • 遍历计算树节点个数
      • 代码部分
    • 计算二叉树的深度
      • 思路
      • 代码部分
    • 第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);
	}

结束

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

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

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

相关文章

java获取星期几

如果你要问 java什么时候学习比较好&#xff0c;那么答案肯定是 java的星期几。 在 Java中&#xff0c;你可以使用 public static void main &#xff08;&#xff09;方法来获取一个类的所有成员变量&#xff0c;然后在所有类中调用这个方法来获取对象的所有成员变量。它能以对…

MCSM面板一键搭建我的世界服务器-外网远程联机【内网穿透】

文章目录 前言1.Mcsmanager安装2.创建Minecraft服务器3.本地测试联机4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射内网端口 5.远程联机测试6. 配置固定远程联机端口地址6.1 保留一个固定TCP地址6.2 配置固定TCP地址 7. 使用固定公网地址远程联机 转载自远程穿透文章&…

【C++】模拟实现map和set

1.关联式容器 关联式容器也是用来存储数据的&#xff0c;与序列式容器不同的是&#xff0c;其里面存储的是结构的 键值对&#xff0c;在数据检索时比序列式容器效率更高。 2 .键值对 用来表示具有一一对应关系的一种结构&#xff0c;该结构中一般只包含两个成员变量key和val…

2023-04-16 学习记录--C/C++-邂逅C/C++(上)

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、固定格式 ⭐️ stdio的理解: abbr.标准输入输出&#xff08;standard input/output&#xff09;。 #include <stdio.h>…

【LeetCode:72. 编辑距离 | 暴力递归=>记忆化搜索=>动态规划 】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

【Linux篇】Shell脚本语法

前言 在安卓源码里&#xff0c;离不开两个东西&#xff0c;一个就是.sh文件&#xff0c;还有一个就是.mk文件。 这两个文件各持有一个语法&#xff0c;一个是Makefile语法&#xff0c;一个是Shell脚本语法。 这两个是真的让我头疼&#xff0c;就像看天书一样&#xff0c;呜呜…

Mysql为json字段创建索引的两种方式

目录 一、前言二、通过虚拟列添加索引&#xff08;Secondary Indexes and Generated Columns&#xff09;三、多值索引&#xff08;Using multi-valued Indexes&#xff09;四、官网地址 一、前言 JSON 数据类型是在mysql5.7版本后新增的&#xff0c;同 TEXT&#xff0c;BLOB …

国内首款多节点/无需密钥/无需登录的ChatGPT客户端开源项目

在这个AI浪潮推动下&#xff0c;涌现了一大批“参差不齐”的GPT产品&#xff0c;有的一直在更新迭代&#xff0c;有的不断升级乃至付费订阅&#xff0c;有的中途停止运营。在这个AI产品也需要优胜劣汰的时代下&#xff0c;谁能够“谁主沉浮&#xff0c;且看今朝&#xff01;”&…

Ansible的基础了解

目录 第一章.Ansible概述 1.1.Ansible是什么 1.2.Ansible的特性和过程 1.3.ansible 具有如下特点&#xff1a; 1.4.Ansible的四个组件 1.5.ansible 核心程序 1.6.ansible执行的过程 第二章.Ansible 环境安装部署 2.1.实验环境&#xff0c;安装部署 第三章.ansible 命…

BLE调制与解调的一些东西

BLE调制 BLE是GFSK的IQ调制 IQ调制 所谓IQ调制&#xff0c;就是利用IQ两个分量序列去控制两路正交信号&#xff0c;I和Q两个序列可以是任意数字&#xff0c;也可以是符合某些规律的序列。 总的原理公式就是&#xff1a; cos(ab)cos(a)cos(b)-sin(a)sin(b) Acos(b)-Bsin(b)M…

音视频 FFmpeg

文章目录 前言视频编解码硬件解码(高级)软解码(低级)软、硬解码对比视频解码有四个步骤Android 系统中编解码器的命名方式查看当前设备支持的硬解码 基础知识RGB色彩空间常见的格式对比YUV索引格式分离RGB24像素数据中的R、G、B分量 BMP 文件格式格式组成像素排列顺序RGB24格式…

双指针技巧总结

一、双指针技巧——情景1 通常&#xff0c;我们只需要一个指针进行迭代&#xff0c;即从数组中的第一个元素开始&#xff0c;最后一个元素结束。然而&#xff0c;有时我们会使用两个指针进行迭代。 双指针的典型场景 (1)从两端向中间迭代数组。 (2)一个指针从头部开始&#…

Spark RDD (Resilient Distributed Datasets) 弹性分布式数据集

设计需求 Spark RDD 的设计目的是为了实现快速、可扩展和容错的数据处理。它是一个不可变的分布式数据集&#xff0c;可以在集群中分布式存储和处理数据。RDD 提供了一系列操作来处理数据&#xff0c;包括转换操作和行动操作。转换操作可以将一个 RDD 转换为另一个 RDD&#x…

Arduino学习笔记4

一.声控灯实验 1.源代码 int led2;//定义板子上数字2口控制小灯 int flag0;//定义一个变量记录小灯是亮起还是熄灭 int shengyin3;//定义声音传感器的控制口void setup() {pinMode(led,OUTPUT);//定义小灯为输出模式pinMode(shengyin,INPUT);//定义声音控制口为输入模式 } vo…

python+Django社区疫情防控系统 uniapp微信小程序

随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&#xf…

[jenkins自动化2]: linux自动化部署方式之流水线(下篇)

目录 1. 引言: 2. 进阶操作 流水线 -> 2.1 简介: -> 2.2 最终效果图展示: -> 2.3 有没有心动, 真的像流水线一样, 实现了一键部署启动 3. 实现方式 3.1 下载几个插件 3.2 创建流水线任务 3.3 点击配置 3.4 根据流水线语法 写一个简单的helloworld 3.5 执行…

数字化医院PACS影像系统 三维影像后处理技术应用

PACS影像存取与传输系统以实现医学影像数字化存储、诊断为核心任务&#xff0c;从医学影像设备&#xff08;如CT、CR、DR、MR、DSA、RF等&#xff09;获取影像&#xff0c;集中存储、综合管理医学影像及病人相关信息&#xff0c;建立数字化工作流程。 PACS系统可实现检查预约、…

【C++入门】内联函数

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【C之路】 目录 什么是内联函数内联函数特性 什么是内联函数 内联函数概念&#xff1a; 内联函数就是以inline修饰的函数叫做内联函数&a…

No.051<软考>《(高项)备考大全》【冲刺5】《软考之 119个工具 (3)》

《软考之 119个工具 &#xff08;3&#xff09;》 41.进度计划编制工具:42.绩效审查:43.卖方投标分析:44.质量成本:45.成本汇总:46.历史关系:47.资金限制平衡:48.挣值管理:49.预测:50.完工尚需绩效指数:51.成本效益分析:52.试验设计:53.七种基本质量工具:54.统计抽样:55.其他质…