数据结构——二叉树的操作 (层序遍历)(C++实现)

数据结构——二叉树的操作(2)(C++实现)

  • 统计叶子结点个数
  • 统计结点个数
  • 层序遍历
    • 非递归方式
    • 递归方式

我们今天接着来看二叉树的操作,如果还没有看过上一篇的可以点击这里:

https://blog.csdn.net/qq_67693066/article/details/138163494

统计叶子结点个数

叶子结点就是左右孩子都没有的结点:
在这里插入图片描述判断叶子结点就是判断是否有左右孩子,如果都没有就为叶子结点:

        if(root->_leftChild== nullptr && root->_rightChild == nullptr){return 1;}

除了判断本身是否为叶子结点,我们也要到它的左右子树去看是否有叶子结点:

       if(root->_leftChild== nullptr && root->_rightChild == nullptr){return 1;}return _TotalLeaves(root->_leftChild) +_TotalLeaves(root->_rightChild);

同时,我们要防止空树的情况:

    //叶子结点int _TotalLeaves( _Node* const& root){if(root == nullptr){return 0;}if(root->_leftChild== nullptr && root->_rightChild == nullptr){return 1;}return _TotalLeaves(root->_leftChild) +_TotalLeaves(root->_rightChild);}

我们再封装一次:

    //叶子结点个数int TotalLeaves(){return _TotalLeaves(_root);}

我们可以测试一下:

#include "BTree.h"int main()
{BTree<int> bt;bt.Insert(20);bt.Insert(12);bt.Insert(35);bt.Insert(22);bt.Insert(1);bt.PrveOrder();std::cout<<std::endl;bt.InOrder();std::cout<<std::endl;bt.PostOrder();std::cout<<std::endl;std::cout <<"叶子结点个数:" << bt.TotalLeaves() << std::endl;return 0;
}

在这里插入图片描述

统计结点个数

统计结点个数,相对来说更简单,只要是一个结点,我们就返回1,表示一个结点:

    //统计结点个数int _NodeNumbers( _Node* const& root){//防止空树的情况if(root == nullptr){return 0;}return 1;}

统计完当前结点,还要统计它的左右子树的结点个数:

    int _NodeNumbers( _Node* const& root){//防止空树的情况if(root == nullptr){return 0;}return 1 + _NodeNumbers(root->_leftChild)+ _NodeNumbers(root->_rightChild); //本身 + 它的左右子树}
#include "BTree.h"int main()
{BTree<int> bt;bt.Insert(20);bt.Insert(12);bt.Insert(35);bt.Insert(22);bt.Insert(1);bt.PrveOrder();std::cout<<std::endl;bt.InOrder();std::cout<<std::endl;bt.PostOrder();std::cout<<std::endl;std::cout <<"叶子结点个数:" << bt.TotalLeaves() << std::endl;std::cout <<"结点个数:" << bt.NodeNumber() << std::endl;return 0;
}

在这里插入图片描述

层序遍历

层序遍历是一种较为特殊的遍历方式,它不依靠根,左子树,右子树的顺序,它是依靠二叉树的层数来遍历:
在这里插入图片描述
层次遍历是依次遍历各层的元素的算法,这种算法遍历出来就是每层的元素顺序。

层次遍历算法中我们要借助我们之前学过的数据结构——队列,因为在层次遍历算法中,我们依次要打印左孩子,右孩子,所以我们借助队列的性质,先入左孩子,然后出队时,左孩子最先被处理:

首先,每一层我们都可以用一个vector来储存:
在这里插入图片描述
然后用一个大的vector来储存这些vector:
在这里插入图片描述
然后我们用queue先压入根节点:
在这里插入图片描述然后20是第一层的vector,我们就压入第一层的vector:
在这里插入图片描述然后弹出20,将20的左孩子右孩子压入queue中:
在这里插入图片描述
然后将12压入vector[1],然后将12的左右孩子压入queue:

在这里插入图片描述然后将35压入vector[1]中,然后同样将35的左右孩子压入queue:
在这里插入图片描述然后同样的方法,将剩下的元素压入下一层的vector。了解了思想之后,我们开始写代码:

非递归方式

    // 定义一个函数 LevelOrder,用于实现二叉树的层序遍历std::vector<std::vector<T>> _LevelOrder(_Node* const& root){// 初始化结果容器,用于存放层序遍历得到的数据,每一层数据作为一个子向量存入std::vector<std::vector<T>> result;// 使用队列辅助遍历,初始时仅包含根节点std::queue<_Node*> queue;// 如果根节点为空,则直接返回空结果集if (!root){return result;}// 将根节点压入队列queue.push(root);// 当队列非空时,继续进行遍历while (!queue.empty()){// 初始化一个临时向量,用于存储当前层的所有节点数据std::vector<T> curResult;// 记录当前层队列的大小(即节点数)int curSize = queue.size();// 遍历当前层的所有节点for (int i = 0; i < curSize; i++){// 弹出队首节点_Node* front = queue.front();queue.pop();// 将当前节点的数据添加到当前层结果向量中curResult.push_back(front->_data);// 若当前节点有左子节点,将其压入队列,等待下一层遍历if (front->_leftChild)queue.push(front->_leftChild);// 若当前节点有右子节点,将其压入队列,等待下一层遍历if (front->_rightChild)queue.push(front->_rightChild);}// 将当前层遍历结果添加到总结果集中result.push_back(curResult);}// 遍历完成后,返回层序遍历结果集return result;}

递归方式

除了非递归方式,我们发现上面的方式都是一个模子里面刻出来的,所以我们也可以用递归的方式:

如果用递归方式,我们就不用队列来辅助了,因为每一次递归都会开一个新的函数栈帧,我们可以利用这个栈帧来区分层次:

// 定义一个成员函数 LevelOrder,用于获取二叉树的层序遍历结果
std::vector<std::vector<T>> LevelOrder()
{// 初始化结果容器,用于存放层序遍历得到的数据,每一层数据作为一个子向量存入std::vector<std::vector<T>> result;// 调用辅助递归函数,从根节点开始遍历LevelOrderHelper(_root, 0, result);// 返回层序遍历结果集return result;
}// 定义一个私有辅助递归函数 LevelOrderHelper,用于实现二叉树的层序遍历
void LevelOrderHelper(_Node* root, int level, std::vector<std::vector<T>>& result)
{// 如果当前节点为空,直接返回if (!root){return;}// 如果当前层级超出了结果容器的范围,添加一个新的子向量if (result.size() <= level){result.push_back(std::vector<T>());}// 将当前节点的数据添加到对应层级的子向量中result[level].push_back(root->_data);// 递归遍历左子树,传入下一层级编号LevelOrderHelper(root->_leftChild, level + 1, result);// 递归遍历右子树,传入下一层级编号LevelOrderHelper(root->_rightChild, level + 1, result);
}

这段代码定义了一个成员函数 LevelOrder,用于获取当前二叉树的层序遍历结果。它首先初始化一个结果容器,然后调用私有辅助递归函数 LevelOrderHelper,从根节点开始遍历,并将遍历结果存储在结果容器中。最后返回这个结果容器。

辅助递归函数 LevelOrderHelper 接收当前节点、所在层级以及结果容器作为参数。递归过程中,首先检查当前节点是否为空,若为空则直接返回。接着检查当前层级是否已存在于结果容器中,若不存在则添加一个新子向量。然后将当前节点数据添加到对应层级的子向量中。最后分别递归遍历左、右子树,传入下一层级编号。

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

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

相关文章

来自异国的客人 - 华为OD统一考试(D卷)

OD统一考试(D卷) 分值: 100分 题解: Java / Python / C++ 题目描述 有位客人来自异国,在该国使用m进制计数。 该客人有个幸运数字n(n<m),每次购物时,其总是喜欢计算本次支付的花费(折算为异国的价格后)中存在多少幸运数字。 问: 当其购买一个在我国价值k的产品时,…

【Leetcode每日一题】 穷举vs暴搜vs深搜vs回溯vs剪枝_全排列 - 子集(难度⭐⭐)(65)

1. 题目解析 题目链接&#xff1a;78. 子集 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 算法思路详解&#xff1a; 为了生成数组 nums 的所有子集&#xff0c;我们需要对数组中的每个元素进行“选择”或“不选择…

JavaScript-Vue入门

本文主要测分享Vue的一些基础 Vue简介 Vue.js 是一个构建数据驱动的 web 界面的渐进式框架。它的主要目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 下是一些 Vue 的主要特点和概念&#xff1a; 1. 响应式数据绑定&#xff1a;Vue 使用基于 HTML 的模板语法…

Visual Studio安装MFC开发组件

MFC由于比较古老了&#xff0c;Visual Studio默认没有这个开发组件。最近由于一些原因&#xff0c;需要使用这个库&#xff0c;这就需要另外安装。 参考了网上的一些资料&#xff0c;根据实际使用&#xff0c;其实很多步骤不是必须的。 https://zhuanlan.zhihu.com/p/68117276…

Neo-reGeorg(webshell代理)-php

https://github.com/L-codes/Neo-reGeorg python加载需要的库 pip install requests 生成webshell代理文件 python .\neoreg.py generate -k 123456 其中&#xff0c;123456为密码&#xff0c;可以修改 生成后的文件路径&#xff1a; > neoreg_servers/tunnel.ashx …

Java后台开发的前置说明

1.知识点逻辑 一个部分 都是先挑重点知识点讲解 然后根据这些重点知识点去完成一个项目的开发 然后在到返回来解决这个部分其他细枝末节的知识点 2.软件开发的分工 我们大致可以将软件开发分成四块&#xff1a; 1.前端开发(比如开发电脑中的京东 htmlcssjavascript) 2.移动开…

什么是主数据管理?合理管理主数据,奠定企业数据战略基石

主数据&#xff08;Master Data&#xff09;是指在企业多个业务系统中重复使用、共享的、具有高价值的核心业务实体数据&#xff0c;如客户、产品、供应商、员工等&#xff0c;它们是企业运营和决策的基础&#xff0c;需要保持高度的准确性、一致性和完整性&#xff0c;以确保业…

Scala 05 —— 函数式编程底层逻辑

Scala 05 —— 函数式编程底层逻辑 该文章来自2023/1/14的清华大学交叉信息学院助理教授——袁洋演讲。 文章目录 Scala 05 —— 函数式编程底层逻辑函数式编程假如...副作用是必须的&#xff1f;函数的定义函数是数据的函数&#xff0c;不是数字的函数如何把业务逻辑做成纯函…

贪吃蛇详解

Win32 API介绍&#xff1a; 在写贪吃蛇这款游戏时需要用到一些有关Win32 API的知识&#xff0c; 接下来我会将设计到的知识点列举并讲解&#xff1a; 首先我们先了解一下Win32 API是什么&#xff0c;Windows这个多作业系统除了协调应⽤程序的执⾏、分配内存、管理资源之外&am…

普乐蛙VR航天航空体验馆VR双人旋转座椅元宇宙VR飞船

多长假来袭&#xff01;&#xff01;想为门店寻找更多新鲜有趣的吸粉体验&#xff1f;想丰富景区体验&#xff1f;别着急&#xff0c;小编为你准备了一款爆款设备——时光穿梭机&#xff0c;720无死角旋转&#xff01;&#xff01;吸睛、刺激体验&#xff0c;将亲子、闺蜜、情侣…

Java对象不再使用时,为什么要赋值为 null

相信大家在面试Java开发的时候,会遇到比较多的问题是Java的内存管理,这里面涉及到Java垃圾回收机制,以及JVM调优等等,那么今天跟大家讨论一个问题:Java对象不再使用时,为什么要赋值为 null ? 1、Java内存管理 在Java中,对象是在堆内存中分配的。 这部分内存用于存储…

科技论文网站:中国科技论文在线

文章目录 1. Intro2. Main3. Cons Evaluation彩蛋&#xff1a;科学素质 这是作者最后一次发 这种类型的宣传 科普文章 1. Intro 中国科技论文在线是经教育部批准&#xff0c;由教育部科技发展中心主办&#xff0c; 利用现代信息技术手段&#xff0c;打破传统出版物的概念&…

Scrapy爬虫框架入门(豆瓣电影Top 250)

文章目录 Scrapy 官网Scrapy 文档GithubScrapy 简介项目结构爬虫实现XPath 教程创建 Scrapy 项目配置用户代理网页 dom 元素 IP 代理池IP代理池作用配置IP代理池申请IP代理池 Scrapy 官网 https://scrapy.org/ Scrapy 文档 https://docs.scrapy.org/en/latest/ Github htt…

在windows上安装MySQL数据库全过程

1.首先在MySQL的官网找到其安装包 在下图中点击MySQL Community(gpl) 找到MySQL Community Server 选择版本进行安装包的下载 2.安装包&#xff08;Windows (x86, 64-bit), MSI Installer&#xff09;安装步骤 继续点击下一步 继续进行下一步&#xff0c;直到出现此界面&#…

Vue3+vite优化基础架构(1)--- 使用unplugin-vue-components

Vue3vite优化基础架构&#xff08;1&#xff09;--- 使用unplugin-vue-components 说明安装unplugin-vue-componentsvite.config.js中使用unplugin-vue-components/vite 说明 这里记录下自己在Vue3vite的项目使用unplugin-vue-components/vite来自定义组件自动全局引入svg雪碧…

【八股】Spring Boot

SpringBoot是如何实现自动装配的&#xff1f; 首先&#xff0c;SpringBoot的核心注解SpringBootApplication里面包含了三个注解&#xff0c;SpringBootConfigurationEnableAutoConfigurationComponentScan&#xff0c;其中EnableAutoConfiguration是实现自动装配的注解&#x…

用自然语言连接系统的认知,用Function Calling 连接大模型和业务

前言 本篇文章&#xff0c;我们重点介绍Function Calling的机制和应用&#xff0c;在其原理上&#xff0c;也讲解了为什么会有plugin、GPTs出现等等。 核心要点&#xff1a; 1.大模型应用的一切&#xff0c;是自然语言连接系统的认知 2.在Function Calling的应用中&#xff0…

重要文件怕丢失怎么办?汇帮数据备份软件帮你解决文件丢失的烦恼 帮你实现文件实时备份的好方法

随着数字时代的来临&#xff0c;电脑文件已成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;无论是个人用户还是企业用户&#xff0c;都可能面临数据丢失的风险&#xff0c;如硬盘故障、病毒攻击、误删除等。为了确保数据安全&#xff0c;实现电脑文件的实时备份变…

等保合规:保护企业网络安全的必要性与优势

前言 无论是多部网络安全法律法规的出台&#xff0c;还是最近的“滴滴被安全审查”事件&#xff0c;我们听得最多的一个词&#xff0c;就是“等保。” 只要你接触安全类工作&#xff0c;听得最多的一个词&#xff0c;一定是“等保。” 那么&#xff0c;到底什么是“等保”呢…

Redis网络相关的结构体 和 reactor模式

目录 1. epoll的封装 结构体aeApiStae 创建epoll fd的封装 epoll_ctl的封装 epoll_wait的封装 2. 结构体aeFileEvent、aeFiredEvent、aeTimeEvent 结构体aeFileEvent 结构体aeFiredEvent 结构体aeTimeEvent 3. struct aeEventLoop aeEventLoop相关的函数 1. 创建eve…