二叉树的遍历(非递归)

news2024/11/16 4:38:06

二叉树的遍历

遍历二叉树, 是指按一定的规则和顺序访问二叉树的所有结点, 使每一个结点都被访问一次, 而且只被访问一次.

由于二叉树是非线性结构, 因此, 二叉树的遍历实质上是将二叉树的各个结点排列成一个线性序列.

DFS: 前序, 中序及后序.

BFS: 是指沿着二叉树的宽度优先遍历二叉树的结点, 即从上到下从左到右逐层遍历二叉树的结点.

前序遍历

访问根结点(N), 前序遍历左子树(L), 前序遍历右子树®, 也即NLR.

也可以是NRL, 因为这两种遍历方法都是先访问根结点, 所以没有区别, 掌握其中一种, 另一种也随之掌握.

image-20230109211219716

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

非递归思路: 二叉树的前序遍历

  1. 对于给定根结点root, 依次从根结点root向左路结点遍历, 直到curr为空并在遍历途中访问对应结点的val, 然后将结点依次入栈.
  2. 当curr为空时, pop栈顶结点, 将栈顶结点的右子树根结点赋值给curr, 并继续转换成从根向左路遍历.
	// 二叉树的前序非递归遍历
    vector<int> preorderTraversal(TreeNode* root) 
	{

        stack<TreeNode*> st;

        vector<int> v;

        TreeNode* curr=root;

        while(curr!=nullptr||!st.empty())
        {   

            while(curr!=nullptr)
            {
                v.push_back(curr->val);
                st.push(curr);

                curr=curr->left;
            }

            TreeNode* top=st.top();
            st.pop();
            
            curr=top->right;

            /*
            // 当curr为空时,遍历左路结点的右子树
            if(curr==nullptr)
            {
                TreeNode* top=st.top();
                st.pop();
                
                curr=top->right;
            }
            else // 当curr不为空时,遍历左路结点
            {
                v.push_back(curr->val);
                st.push(curr);
                
                curr=curr->left;
            }
            */
        }

        return v;
    }

中序遍历

中序遍历左子树, 访问根结点, 中序遍历右子树, 也即LNR.

或者RNL.

image-20230109212500640

给定一个二叉树的根节点 root ,返回 它的 中序 遍历

非递归思路: 二叉树的中序遍历

  1. 中序非递归与前序非递归思路相似, 只是访问结点的val时机不同.
  2. 对于给定根结点root, 依次从根结点root向左路结点遍历, 直到curr为空并在遍历途中将结点依次入栈.
  3. 当curr为空时, pop栈顶结点, 先访问栈顶结点的val, 再将栈顶结点的右子树根结点赋值给curr, 并继续转换成从根向左路遍历.
	vector<int> inorderTraversal(TreeNode* root) 
    {
        std::vector<int> v;
        std::stack<TreeNode*> st;

        TreeNode* curr=root;
		// 思路与前序遍历相似
        while(curr!=nullptr || !st.empty())
        {
            while(curr!=nullptr)
            {
                st.push(curr);
                
                curr=curr->left;
            }
            TreeNode* top=st.top();
            st.pop();
            // 只是访问TreeNode的val时机不同
            v.push_back(top->val);
            curr=top->right;
        }
        return v;

        // vector<int> v;
        // stack<TreeNode*> st;

        // TreeNode* curr=root;

        // while(curr!=nullptr || !st.empty())
        // {
        //     if(curr!=nullptr)
        //     {
        //         st.push(curr);
        //         curr=curr->left;
        //     }
        //     else
        //     {
        //         TreeNode* top=st.top();
        //         st.pop();
                
        //         v.push_back(top->val);

        //         curr=top->right;
        //     }
        // }
        // return v;
    }

后序遍历

**后序遍历左子树, 后序遍历右子树, 访问根结点, 也即LRN. **

或者RLN.

image-20230109213035617

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历

非递归思路: 二叉树的后序遍历

  1. 后序遍历与前中序遍历有一定差异, 在后序遍历过程中, 需要prev来记录访问结点的前一个, 用来判定该不该访问根结点.
  2. 对于给定根结点root, 依次从根结点root向左路结点遍历, 直到curr为空并在遍历途中将结点依次入栈.
  3. 当curr为空时, 根据栈顶结点的右孩子right, 来判断是否pop. 如果right为空或者right为prev说明右子树为空或者右子树访问完, 所以可以pop,并访问该栈顶结点的val, 最后更新prev.
  4. 如果以上两点不满足, 则说明右子树还未访问, 栈顶元素还不能pop, 需要更新curr为栈顶结点的右孩子继续访问.
	vector<int> postorderTraversal(TreeNode* root) 
	{
        TreeNode* curr=root;
        TreeNode* prev=nullptr; // 记录遍历结点的前一个

        vector<int> v;
        stack<TreeNode*> st;

        while(curr!=nullptr || !st.empty())
        {
            while(curr!=nullptr)
            {
                st.push(curr); // 将结点入栈
                curr=curr->left;
            }

            TreeNode* top=st.top();
            // 当右子树为空或者右子树被访问过,才pop
            if(top->right==nullptr || top->right==prev)
            {
                prev=top;
                v.push_back(top->val);
                st.pop();
            }
            else // 否则先访问右子树,等右子树访问完成,才反过来访问根,不能pop
            {
                curr=top->right;
            }
        } 
		
        /*while(curr!=nullptr|| !st.empty())
        {
            if(curr!=nullptr)
            {
                st.push(curr);

                curr=curr->left;
            }
            else
            {
               TreeNode* top=st.top();

                // 当右子树为空或者右子树被访问过,才pop
               if(top->right==nullptr || top->right==prev)
               {    
                   v.push_back(top->val);

                   st.pop();

                   prev=top;
               }
               else
               {
                   curr=top->right;
               }
            }
        }*/
        
        return v;
    }

层序遍历

层序遍历就是根据二叉树的结构从上到下从左到右逐层遍历二叉树的结点.

image-20230109214951059

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

基本思路: 二叉树的层序遍历

  1. 初始化一个队列, 并把根结点入队.
  2. 当队列非空时, 循环执行步骤3到步骤5, 否则遍历结束.
  3. 出队一个结点, 并访问该结点.
  4. 若该结点的左子树非空, 则将其左子树入队.
  5. 若该结点的右子树非空, 则将其右子树入队.

需要注意: 当某一层走完时, 该层的下一层也随之全部进入队列中.

	vector<vector<int>> levelOrder(TreeNode* root) 
    {
        queue<TreeNode*> q;

        vector<vector<int>> vv;
        int levelSize=0; // 记录某一层有多少个结点
        
        if(root!=nullptr)
        {
            q.push(root);
            ++levelSize; // 刚开始根结点这一层就一个结点
        }
        
        while(!q.empty())
        {
            vector<int> v;
            
            // 将该层的结点都遍历完
            for(size_t i=0;i<levelSize;i++)
            {
                TreeNode* front=q.front();
                q.pop();
                
                v.push_back(front->val);
                
                if(front->left!=nullptr)
                {
                    q.push(front->left);
                }
                
                if(front->right!=nullptr)
                {
                    q.push(front->right);
                }
            }
            // 遍历完成,队列中的个数就是下一层结点的个数
            levelSize=q.size(); 
            vv.push_back(v);
        }
        return vv;
    }
 
                if(front->right!=nullptr)
                {
                    q.push(front->right);
                }
            }
            // 遍历完成,队列中的个数就是下一层结点的个数
            levelSize=q.size(); 
            vv.push_back(v);
        }
        return vv;
    }

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

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

相关文章

Leetcode.1806 还原排列的最少操作步数

题目链接 Leetcode.1806 还原排列的最少操作步数 题目描述 给你一个偶数 ​n​n​n​​​​​ &#xff0c;已知存在一个长度为 nnn 的排列 permpermperm &#xff0c;其中 perm[i]iperm[i] iperm[i]i​&#xff08;下标 从 0 开始 计数&#xff09;。 一步操作中&#xff0…

OLAP和OLTP的区别

OLAP和OLTP的区别 OLAP&#xff1a; (Online transaction processing):在线/联机事务处理。典型的OLTP类操作都比较简单&#xff0c;主要是对数据库中的数据进行增删改查&#xff0c;操作主体一般是产品的用户。 OLTP&#xff1a; (Online analytical processing):指联机分…

Vue新一代状态管理工具—Pinia—都2023年了,快学起来吧!

Pinia 基本介绍 Pinia 是 Vue.js 的轻量级状态管理库 官方网站&#xff1a;https://pinia.vuejs.org/ 中文文档: https://pinia.web3doc.top/introduction.html 为什么学习pinia? pinia和vuex4一样&#xff0c;也是vue 官方 状态管理工具(作者是 Vue 核心团队成员&#xff…

基于JAVA SSM框架的影院管理系统源码,实现包括影院管理,电影管理,影厅管理,排片管理,选座售票,演员管理,影片评论等功能

介绍 下载地址&#xff1a;基于JAVA SSM框架的影院管理系统源码 该项目是一个电影信息管理、发布、展示平台&#xff0c;终端用户可以浏览、购票、评论。项目主要实现包括影院管理&#xff0c;电影管理&#xff0c;影厅管理&#xff0c;排片管理&#xff0c;选座售票&#xff…

连号区间数(第四届蓝桥杯省赛C++B组,第四届蓝桥杯省赛JAVAB组)

题目详细&#xff1a;解题思路&#xff1a;对于这个题目如果一开始没有思路的话我们可以先想一下暴力写法暴力的话就是不断的枚举每个区间然后判断这个区间是否合法这样写下来用了三重循环而对于题目我们只能通过部分样例所以我们就要想办法取缩减它的时间对于遍历每个区间我们…

【SpringBoot】使用AOP+注解实现请求参数的指定自动填充

首先定义一个加在方法上的注解 import java.lang.annotation.*;/*** 开启自动参数填充*/ Retention(RetentionPolicy.RUNTIME) Target({ElementType.METHOD}) Documented Inherited public interface AutoParameterFill {/*** 要填充的字段名,不写的话默认下面类的子类中的字段…

Redis未授权访问漏洞(一)先导篇

前言 Redis默认情况下&#xff0c;会绑定在0.0.0.0:6379&#xff0c;如果没有进行采用相关的策略&#xff0c;比如添加防火墙规则避免其他非信任来源ip访问等&#xff0c;这样将会将Redis服务暴露到公网上。 如果在没有设置密码认证&#xff08;一般为空&#xff09;的情况下…

InceptionNet与ResNet

以下代码图片思路来源&#xff1a; 北京大学Tensor flow笔记 嗯,最近学了一下神经网络&#xff0c;并没有很难&#xff0c;主要是把代码背下来&#xff0c;然后掌握Tensorflow是怎么搭建网络的&#xff0c;Tensorflow是比pytorch好用的&#xff0c;我直接抄的代码里面&#xff…

UDS诊断系列介绍05-27服务

本文框架1. 系列介绍27服务概述2. 27服务请求与应答2.1 27服务请求2.2 27服务肯定应答2.3 27服务否定应答1. 系列介绍 UDS&#xff08;Unified Diagnostic Services&#xff09;协议&#xff0c;即统一的诊断服务&#xff0c;是面向整车所有ECU的一种诊断通信方式&#xff0c;…

java-操作excel

文章目录java操作Excel数据使用场景excel 03 和 07的区别POIeasyExcel解析excel表中的对象POI使用步骤POI 写数据POI 读数据计算公式easyExcel读写数据写数据读数据java操作Excel数据 在 平时 可以使用IO流对Excle进行操作 但是现在使用更加方便的第三方组件来实现 使用场景 1、…

在rhel7系统使用Mariadb

文章目录一 联系和区别二 需求三 部署安装3.1 环境准备3.2 安装软件包3.3 启动服务3.4 设置防火墙策略四 创建用户和库表4.1 登录数据库4.2 创建用户4.3 创建数据库和表五 备份和恢复5.1 备份 com 数据库5.2 模拟误删除操作5.3 恢复表一 联系和区别 Mariadb是由社区开发的一个…

4.4 集成运放的性能指标及低频等效电路

一、集成运放的性能指标 在考察集成运放的性能时&#xff0c;常用下列参数来描述&#xff1a; 1、开环差模增益 AodA_{od}Aod​ 在集成运放无外加反馈时的差模放大倍数称为差模开环增益&#xff0c;记作 AodA_{od}Aod​。AodΔuO/(uP−uN)A_{od}\Delta u_O/(u_P-u_N)Aod​Δ…

【Spring Cloud GateWay】ServerHttpResponseDecorator不生效

文章目录1. BUG描述2. BUG解决3. BUG分析1. BUG描述 在Spring Cloud Gateway使用编码的方式实现一个全局拦截器&#xff0c;在全局拦截器中想要打印响应日志。 于是自己装饰了一个具有打印日志功能的ServerHttpResponseDecorator&#xff0c;但是在转发后的服务返回响应的时候…

在线浏览PDF:Grapecity Documents for PDF Viewer 6.0.2

Grapecity Documents for PDF Viewer跨平台 JavaScript PDF 查看器---备注:必须配合.NET版本才能编辑PDF 使用我们的 JavaScript PDF 查看器在网络上阅读和编辑 PDF。跨浏览器和框架打开和打印。 Grapecity Documents for PDF Viewer全功能的 JavaScript PDF 查看器和 PDF 编辑…

move语言之基础学习(基本类型+表达式+变量)例子

一、基本类型 Move 的基本数据类型包括: 整型 (u8, u64, u128)、布尔型 boolean 和地址 address。 Move 不支持字符串和浮点数。 整型 整型包括 u8、u64 和 u128&#xff0c;我们通过下面的例子来理解整型&#xff1a; script { fun main() { // define empty variable, set…

python(0)计算机基础知识

文章目录计算机是什么计算机的组成计算机的使用方式windows的命令行文本文件和字符集乱码计算机是什么 在现实生活中&#xff0c;越来越无法离开计算机了 电脑、笔记本、手机、游戏机、汽车导航、智能电视。。。 计算机就是一个用来计算的机器 目前来讲&#xff0c;计算机只…

C++模板进阶+继承详解

耕耘和收获不是连贯的&#xff0c;中间还隔着很长一段时间&#xff0c;那就是坚持&#xff01;一&#xff1a;模板进阶1.1&#xff1a;非类型模板参数template<class T,size_t N> class arr { private:T _a[N]; };这里的N就跟define一样&#xff0c;属于非类型模板参数。…

MongoDB常用操作

官网地址&#xff1a;https://www.mongodb.com/docs/manual/reference/method/Date/ 实例&#xff1a;系统上运行的进程及节点集&#xff0c;一个实例可以有多个库&#xff0c;默认端口 27017。如果要在一台机器上启动多个实例&#xff0c;需要设置不同端口和不同的dbpath。库&…

第四章web服务器之httpd

文章目录第四章 web服务器1.1 www简介1.1.1 网址及HTTP简介1.1.2 HTTP协议请求的工作流程1.2 www服务器的类型1.2.1 仅提供用户浏览的单向静态网页1.2.2 提供用户互动接口的动态网站1.3 www服务器的基本配置1.4 实验1.4.1 搭建静态网站——基于http协议的静态网站1.4.2 搭建静态…

Acwing---1211.蚂蚁感冒

蚂蚁感冒1.题目2.基本思想3.代码实现1.题目 长 100 厘米的细长直杆子上有 nnn 只蚂蚁。 它们的头有的朝左&#xff0c;有的朝右。 每只蚂蚁都只能沿着杆子向前爬&#xff0c;速度是 1 厘米/秒。 当两只蚂蚁碰面时&#xff0c;它们会同时掉头往相反的方向爬行。 这些蚂蚁中…