链式二叉树的基本操作,前序、中序以及后序遍历(递归实现,非递归实现)【有图解】

文章目录

  • 结点设置
  • 二叉树的遍历
    • 前序、中序以及后序遍历 递归实现
    • 前序、中序以及后序遍历 非递归实现
    • 层序遍历
  • 结点的个数
  • 叶子结点的个数
  • 第k层结点的个数
  • 值为x的结点
  • 树的最大深度
  • 二叉树的销毁

结点设置

既然是链式二叉树,那必须得有自己的结点类型,以下是链式二叉树结点类型的定义,为了避免过多重复的代码,下面的问题都统一使用该结点类型。

typedef char BTDataType;//结点中存储的元素类型(以char为例)typedef struct BTNode
{BTDataType data;//结点中存储的元素类型struct BTNode* left;//左指针域(指向左孩子)struct BTNode* right;//右指针域(指向右孩子)
}BTNode;

二叉树的遍历

前序、中序以及后序遍历 递归实现

所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。

遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

在这里插入图片描述

按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:

  1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
  2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
  3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。
// 二叉树前序遍历 
void PreOrder(BTNode* root)
{if (root == nullptr){return;}//根->左子树->右子树printf("%c ", root->data);PreOrder(root->left);PreOrder(root->right);
}// 二叉树中序遍历
void InOrder(BTNode* root)
{if (root == nullptr){return;}//根->左子树->右子树PreOrder(root->left);printf("%c ", root->data);PreOrder(root->right);
}
// 二叉树后序遍历
void PostOrder(BTNode* root)
{if (root == nullptr){return;}//根->左子树->右子树PreOrder(root->left);PreOrder(root->right);printf("%c ", root->data);
}

前序遍历递归图解

在这里插入图片描述
在这里插入图片描述

前序、中序以及后序遍历 非递归实现

144.
二叉树的前序遍历

在这里插入图片描述

思路:

  1. 根节点入栈.
  2. 栈顶元素入存入vector,根节点出栈.
  3. 右孩子入栈
  4. 左孩子入栈

因为我们要求:
先访问左孩子,再访问右孩子.
而栈是后进先出的结构,所以:
右孩子先入栈,左孩子后入栈.

步骤示例图:

在这里插入图片描述

代码:

class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {vector<int> v;stack<TreeNode*> s;if(root == nullptr)return {};s.push(root);//根节点先入栈while(!s.empty())//当栈为空时,结束{TreeNode* ret = s.top();v.push_back(ret->val);//出栈前,先将栈顶元素存入vectors.pop();//栈顶元素出栈//栈顶元素的右左子树入栈if(ret->right)s.push(ret->right);if(ret->left)s.push(ret->left);}return v;}
};

94.
二叉树的中序遍历

在这里插入图片描述
思路:
有了前面的前序遍历的思想,对于中序遍历,需要注意的是存入容器(这里是vector)的时机.

左路节点依次入栈.(与前序对比:此时入栈并没有入容器.)
栈顶元素入容器,栈顶元素出栈,栈顶元素的右子树子问题解决.

在这里插入图片描述
代码:

class Solution {
public:vector<int> inorderTraversal(TreeNode* root) {stack<TreeNode*> s1;vector<int> v1;TreeNode*  cur=root;while(cur||!s1.empty()){//沿着左子树一直入节点while(cur){s1.push(cur);cur=cur->left;}TreeNode* top = s1.top();if(top==nullptr)break;v1.push_back(top->val);//栈顶元素出栈s1.pop();//右子树 以子问题的方式解决if(top->right)cur=top->right;}return v1;}
};

145. 二叉树的后序遍历

在这里插入图片描述
思路 :

对于后序遍历,同样注意存入容器的时机,应当是左子树和右子树都访问完毕,才能够访问根节点.

在这里插入图片描述

注意点:

(1)访问结点之前,需要先判断右子树是否已经被访问.

如何判断根节点的右子树已经有没有访问?
答案: 上一个存入的结点是自己右子树,则右子树已经被访问.
上一个结点不是自己的右子树,则右子树未被访问.

代码:

class Solution {
public:vector<int> postorderTraversal(TreeNode* root) {stack<TreeNode*> s;vector<int> v;TreeNode* prev = nullptr;TreeNode* cur = root;while(cur || !s.empty()){while(cur){s.push(cur);cur = cur->left;}TreeNode* top = s.top();//top的结点右为空 or 上一个访问的结点是他的右孩子//说明不用访问 或者 已经访问过了if(top->right == nullptr || top->right == prev){s.pop();prev = top;v.push_back(top->val);}else{cur = top->right;}}return v;}
};

层序遍历

层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。

设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

在这里插入图片描述

思路(借助一个队列):
 1.先把根入队列,然后开始从队头出数据。
 2.出队头的数据,把它的左孩子和右孩子依次从队尾入队列(NULL不入队列)。
 3.重复进行步骤2,直到队列为空为止。

在这里插入图片描述

// 层序遍历
void LevelOrder(BTNode* root)
{std::queue<BTNode*> q;if (root != nullptr)q.push(root);while (q.empty()){BTNode* front = q.front();q.pop();printf("%c ", front->data);//打印出队的元素if (front->left){q.push(front->left);}if (front->right){q.push(front->right);}}
}

结点的个数

求解树的结点总数时,可以将问题拆解成子问题:
 1.若为空,则结点个数为0。
 2.若不为空,则结点个数 = 左子树结点个数 + 右子树结点个数 + 1(自己)。

代码:

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{return root == nullptr ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

叶子结点的个数

子问题拆解:
 1.若为空,则叶子结点个数为0。
 2.若结点的左指针和右指针均为空,则叶子结点个数为1。
 3.除上述两种情况外,说明该树存在子树,其叶子结点个数 = 左子树的叶子结点个数 + 右子树的叶子结点个数。

代码:

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{if (root == nullptr)//空树无叶子结点return 0;if (root->left == nullptr && root->right == nullptr)//是叶子结点return 1;//叶子结点的个数 = 左子树的叶子结点个数 + 右子树的叶子结点个数return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

第k层结点的个数

思路:
 相对于根结点的第k层结点的个数 = 相对于以其左孩子为根的第k-1层结点的个数 + 相对于以其右孩子为根的第k-1层结点的个数。
在这里插入图片描述

代码:

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{if (k < 1 || root == nullptr)//空树或输入k值不合法return 0;if (k == 1)//第一层结点个数return 1;//相对于父结点的第k层的结点个数 = 相对于两个孩子结点的第k-1层的结点个数之和return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

值为x的结点

子问题:
 1.先判断根结点是否是目标结点。
 2.再去左子树中寻找。
 3.最后去右子树中寻找。

代码:

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == nullptr)return nullptr;if (root->data == x)return root;BTNode* rleft = BinaryTreeFind(root->left, x);//在左子树中找if (rleft)return rleft;BTNode* rright = BinaryTreeFind(root->right, x);//在右子树中找if (rright)return rright;return nullptr;//根结点和左右子树中均没有找到
}

树的最大深度

子问题:
 1.若为空,则深度为0。
 2.若不为空,则树的最大深度 = 左右子树中深度较大的值 + 1。

代码:

//树的最大深度
int BinaryTreeMaxDepth(BTNode* root)
{//树的最大深度 = 左右子树中深度较大的值 + 1return root == nullptr ? 0 : (std::max(BinaryTreeMaxDepth(root->left) + 1, BinaryTreeMaxDepth(root->right) + 1));
}

二叉树的销毁

二叉树的销毁,与其他数据结构的销毁类似,都是一边遍历一边销毁。但是二叉树需要注意销毁结点的顺序,遍历时我们应该选用后序遍历,也就是说,销毁顺序应该为:左子树->右子树->根。
 我们必须先将左右子树销毁,最后再销毁根结点,若先销毁根结点,那么其左右子树就无法找到,也就无法销毁了。

代码:

//二叉树销毁
void BinaryTreeDestroy(BTNode* root)
{if (root == NULL)return;BinaryTreeDestroy(root->left);//销毁左子树BinaryTreeDestroy(root->right);//销毁右子树free(root);//释放根结点
}

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

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

相关文章

使用 Docker 搭建 Hadoop 集群

1.1. 启用 WSL 与虚拟机平台 1.1.1. 启用功能 启用 WSL并使用 Moba 连接-CSDN博客 1.2 安装 Docker Desktop 最新版本链接&#xff1a;Docker Desktop: The #1 Containerization Tool for Developers | Docker 指定版本链接&#xff1a;Docker Desktop release notes | Do…

3.若依前端项目拉取、部署、访问

因为默认RuoYi-Vue是使用的Vue2,所以需要另外去下载vue3来部署。 拉取代码 git clone https://gitee.com/ys-gitee/RuoYi-Vue3.git 安装node才能执行npm相关的命令 执行命令npm install 如果npm install比较慢的话&#xff0c;需要添加上国内镜像 npm install --registrhttp…

Docker安装体验kuboard-k8s多集群管理工具

文章目录 1.kuboard是什么&#xff1f;2.docker安装命令2.1 Linux上docker环境安装命令2.2 Windows上docker环境安装命令 3.登录访问3.1首页访问地址3.2 默认账号密码3.3 登录页3.4 首页 4总结 1.kuboard是什么&#xff1f; 参看官网: https://kuboard.cn/gitHub项目地址&…

重学设计模式-责任链模式

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为设计模式&#xff0c;它通过将请求沿着链传递&#xff0c;使多个对象都有机会处理该请求&#xff0c;从而避免了请求的发送者与接收者之间的耦合关系。本文将详细介绍责任链模式的定义、优缺点、应…

SuperMap iClient3D for Cesium等高线标注

kele 前言 在三维地形分析中&#xff0c;等高线分析是一种非常重要的分析方法&#xff0c;它能直观的表达出地形的高低起伏特征&#xff0c;在三维系统中受到广泛应用。在SuperMap iClient3D for Cesium中&#xff0c;等高线分析是前端GPU分析&#xff0c;能够分析并渲染出等高…

简易共享屏幕工具改进版

昨天心血来潮写了一篇关于简易共享屏幕工具的文章&#xff0c;发现也有一些阅读量&#xff0c;并且我对于它的效果不是很满意 &#xff0c;实际呈现的帧率还是太低了。所以我今天换了更高效的方式来实现。 50 行代码简易屏幕共享工具 改进 降低分辨率 昨天那个测试的帧率低&a…

4.银河麒麟V10(ARM) 离线安装 MySQL

1. 系统版本 [rootga-sit-cssjgj-db-01u ~]# nkvers ############## Kylin Linux Version ################# Release: Kylin Linux Advanced Server release V10 (Lance)Kernel: 4.19.90-52.39.v2207.ky10.aarch64Build: Kylin Linux Advanced Server release V10 (SP3) /(La…

图像处理-Ch5-图像复原与重建

Ch5 图像复原 文章目录 Ch5 图像复原图像退化与复原(Image Degradation and Restoration)噪声模型(Noise Models)i.i.d.空间随机噪声(Generating Spatial Random Noise with a Specified Distribution)周期噪声(Periodic Noise)估计噪声参数(Estimating Noise Parameters) 在仅…

「下载」智慧园区及重点区域安全防范解决方案:框架统一规划,建设集成管理平台

智慧园区在基础设施建设和管理上仍存在诸多挑战。园区内场景碎片化、系统独立化、数据无交互、应用无联动等问题普遍存在&#xff0c;导致管理效率低下&#xff0c;安全隐患频发。 各安保系统如视频监控系统、报警管理系统、门禁管理系统等独立运行&#xff0c;数据不共享&…

LeetCode - Google 校招100题 第6天 回溯法(Backtracking) (8题)

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/144743505 LeetCode 合计最常见的 112 题: 校招100题 第1天 链表(List) (19题)校招100题 第2天 树(Tree) (21题)校招100题 第3天 动态规划(DP) (20题)

Elasticsearch检索之三:官方推荐方案search_after检索实现(golang)

Elasticsearch8.17.0在mac上的安装 Kibana8.17.0在mac上的安装 Elasticsearch检索方案之一&#xff1a;使用fromsize实现分页 快速掌握Elasticsearch检索之二&#xff1a;滚动查询(scrool)获取全量数据(golang) 1、search_after检索 在前面的文章介绍了fromsize的普通分页…

网易企业邮箱登陆:保障数据安全

网易企业邮箱是一款为企业提供安全可靠的电子邮件服务的工具。通过网易企业邮箱&#xff0c;企业可以实现员工之间的高效沟通和信息共享&#xff0c;同时保障数据的安全性。 企业邮箱的安全性是企业信息保护的重要组成部分。网易企业邮箱采用了多层加密技术&#xff0c;确保邮件…

3.银河麒麟V10 离线安装Nginx

1. 下载nginx离线安装包 前往官网下载离线压缩包 2. 下载3个依赖 openssl依赖&#xff0c;前往 官网下载 pcre2依赖下载&#xff0c;前往Git下载 zlib依赖下载&#xff0c;前往Git下载 下载完成后完整的包如下&#xff1a; 如果网速下载不到请使用网盘下载 通过网盘分享的文件…

Hive其十,优化和数据倾斜

目录 Hive优化 1、开启本地模式 2、explain分析SQL语句 3、修改Fetch操作 4、开启hive的严格模式【提高了安全性】 5、JVM重用 6、分区、分桶以及压缩 7、合理设置map和reduce的数量 合理设置map数量&#xff1a; 设置合理的reducer的个数 8、设置并行执行 9、CBO优…

uniapp通过v-if进行判断时,会出现闪屏?【已解决】

1.问题&#xff1a;按钮切换时&#xff0c;通过v-if来判断&#xff0c;会出现闪烁情况&#xff0c;影响用户体验 2.v-if 闪烁问题可能的原因 ‌条件切换频繁‌&#xff1a;如果 v-if 指令的条件在短时间内频繁切换&#xff0c;会导致元素不断被销毁和重新创建&#xff0c;从而…

ida的使用

一.ida的基本设置 在IDA的安装根目录下有许多文件夹&#xff0c;各个文件夹存储不同的内容 1.目录结构 cfg&#xff1a;包含各种配置文件&#xff0c;基本IDA配置文件ida.cfg,GUI配置文件idagui.cfg&#xff0c;文本模式用户界面配置文件idatui.cfg, idc&#xff1a;包含…

Faster R-CNN

文章目录 摘要Abstract1. 引言2. 框架2.1 RPN2.1.1 网络结构2.1.2 损失函数2.1.3 训练细节 2.2 训练过程 3. 创新点和不足3.1 创新点3.2 不足 参考总结 摘要 Faster R-CNN是针对Fast R-CNN缺点改进的目标检测模型。为了解决候选区域生成耗时长的问题&#xff0c;Faster R-CNN提…

嵌入式AI STM32部署卷积神经网络的魔法棒

基于STM32部署卷积神经网络控制设备方案-AI项目-STM32部署卷积神经网络方案-红外信号复制方案-轨迹识别 项目包含下述内容 硬件部分、PCB制板、BOM表文件等等 (Hardware)外壳、3D打印文件 (3D_print)软件程序、用于电子法棒的软件程序 AI Keil等等(Software)QT上位机动作识别…

GCP Cloud Observability 是什么,有什么使用场景

GCP Cloud Observability 是 Google Cloud Platform (GCP) 提供的一组工具和服务&#xff0c;用于监控、日志记录、追踪和调试应用程序和基础设施的健康和性能。通过收集和分析遥测数据&#xff08;如指标、日志和追踪信息&#xff09;&#xff0c;Cloud Observability 有助于理…

UE4_用户控件_2_按钮的动态效果

效果展示&#xff1a; 操作步骤&#xff1a; 1、新建一个触发Actor&#xff0c;更名为BP_EventTrigger。 这个蓝图类可以拖拽到场景中好多次&#xff0c;生成好多实例。但是我希望每次触发创建的用户控件都是不同的。添加Capsule Collision。 修改胶囊体半高和半径都为156 BP_…