二叉树遍历的常用方法

二叉树的遍历 先序遍历:1.访问根结点      2.先序遍历根结点的左子树      3.先序遍历根结点的右子树 中序遍历:1.中序遍历根结点的左子树   2.访问根结点     3.中序遍历根结点的右子树 后序遍历:  1.后序遍历根结点的左子树   2.后序遍历根结点的右子树   3.访问根结点  二叉树的顺序存储结构:             二叉树的顺序存储结构是用一组连续的存储单元存 阅读详情

概述

二叉树的遍历可以说是解决二叉树问题的基础。我们常用的遍历方式无外乎就四种前序遍历、中序遍历、后续遍历、层次遍历这四种。其中前三种遍历方式在实现时,即便采用不同的实现方式(递归方式、非递归),它们的算法结构是有很大的相似性。因而针对前三种的遍历我们会总结出对应通用的解决框架,便于在解决二叉树问题时进行使用。

递归方式

递归方式遍历二叉树时,无论是前序遍历、中序遍历还是后续遍历的方式,它们最大的区别就是对节点数据的访问位置不同。除此之外其结构完全一致,因而我们总结出如下的框架结构:

void traverse(TreeNode root) {
    //终止条件
    if(root == null) return;
    // 前序遍历
    traverse(root.left);
    // 中序遍历
    traverse(root.right);
    // 后序遍历
}

对应注释的位置访问数据就可以实现不同的遍历方式。

例如,前序遍历:

void traverse(TreeNode root) {
    if(root == null) return;
    visit(root);
    traverse(root.left);
    traverse(root.right);
}

同样的中序遍历:

void traverse(TreeNode root) {
    if(root ==null) return;
    traverse(root.left);
    visit(root);
    traverse(root.right);
}

后续遍历:

void traverse(TreeNode root) {
    if(root ==null) return;
    traverse(root.left);
    traverse(root.right)
}

img

是否非常easy!!

非递归方式

二叉树非递归遍历说实话有很多种实现方式,但本质上都是模拟整个遍历的过程来实现的。

为了便于理解,其中前序遍历、中序遍历、后序遍历我们采用一套类似的算法框架。

整个算法框架如下:

public void tranverse(TreeNode root) {
    // 边界判断
    if (root == null) {
      return;
    }
    Stack<TreeNode> stack = new Stack<>();
    TreeNode current = root;
    while (current != null || !stack.isEmpty()) {
       //节点非空时,证明父节点的左侧节点非空,直接入栈
      if (current != null) {
        //前序遍历 visit(current)
        stack.push(current);
        current = current.left;
      } else {
        //节点为空,证明左侧节点为空,出栈,更换游标节点方向
        current = stack.pop();
		//中续遍历 visit(current);
        current = current.right;
      }
    }
  }

后序遍历它的遍历顺序为"左-->右-->根",较之与前序遍历的"根-->左-->右",好像是有很大的相似性,我们能否针对上边的框架进行修改,使由前序遍历转换成后序遍历??
答案是肯定的,我们可以观察到,可以先求出遍历顺序是"根-->右-->左""的节点序列,再倒序,便刚好是后序遍历的顺序:左右根。而遍历顺序是根右左的话,很好办,从前序遍历的代码中改两行就是了。

故而,可以选择使用两个栈,其中一个用于遍历,另一个用于结果的倒序。

实现代码如下:

//使用双栈来实现后序遍历
  public void postOrderTraverse(TreeNode root){
    Stack<TreeNode> stack = new Stack<>();
    Stack<Integer> res = new Stack<>();
    TreeNode cur = root;
    while (cur!=null || !stack.isEmpty()) {
      if (cur!=null){
        stack.push(cur);
        res.push(cur.val);
        cur = cur.right; //修改处
      }else{
        cur = stack.pop();
        cur = cur.left;  // 修改处
      }
    }
    while (!res.isEmpty()){
      visit(res.pop());
    }
  }

至此,非递归遍历完成,是不是也很easy!!

下边我们可以看一下最后一种层次遍历

层次遍历

层次遍历本质上就是阉割版广度优先遍历,关于BFS我之前也写了一篇文章BFS与DFS套路总结,感兴趣的小伙伴可以去读一下。我们此处就直接给出BFS算法的框架:

/**
* 给定起始节点start和目标节点target,返回其最短路径长度
**/
int BFS(Node start,Node target){
    Queue<Node> q; //核心数据结构
    Set<Node> visited: //某些情况下可以通过byte数组来进行代替
    int step = 0; //记录扩散步数
    //起始节点入队列
    q.add(start);
    visited.offer(start);
    while(q not empty) {
        //必须要用sz来保存q.size(),然后扩散sz不能直接使用q.size()
        int sz = q.size();
        //将队列中的节点进行扩散
        for(int i =0 ; i < sz; i++) {
            Node cur = q.poll();
            // 目标节点判断
            if(cur is target) {
                return step;
            }
            // 邻接结点入队列
            for(Node n:cur.adjs) {
                //未访问节点入队列
                if(n is not int visited) {
                    visitd.add(n);
                    q.offer(n);
                }
            }
        }
        // 更新步数
        step++;
    }
}

此处我们借助BFS的框架,直接给出其实现方法:

void LevelOrder(TreeNode root){
    //初始化栈,并放入
    Queue<TreeNode> queue;
    queue.add(root);
    while( !queue.isEmpty()) {
        //出栈
        TreeNode cur = queue.poll();
        //访问节点
        visit(cur);
        //向下一层级扩散
        if(cur.left !=null) queue.add(cur.left);
        if(cur.right !=null) queue.add(cur.right);
    }
}

较之于BFS,我们会发现,层次遍历,少了好多东西,比如不需要visited来标记已访问的节点(二叉树本身结构的特点,不可能出现重复遍历),也不需要将队列中的节点进行扩散等。

总结

至此,二叉树的四种遍历方式总结完成。我们发现其实二叉树所有的遍历方式都有一种通用的算法框架,只要掌握算法本身的框架还是比较容易能够写出实现代码的。

参考

  1. https://www.cnblogs.com/kangna/p/11846156.html

  2. https://zhuanlan.zhihu.com/p/80578741

二叉树的遍历(七种方法) 本章主要通过运用递归与非递归方法分别对二叉树进行遍历 主要分先序遍历、中序遍历、后序遍历以及层次遍历四种情况进行讨论 阅读详情

相关推荐

android10 部分机型(华为)无法正常更新安装app

android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=file://storage/emulated/0/文件夹名/***.apk typ=application/vnd.android.package-archive }

森森先生的博客 3927

数据结构--二叉树遍历(详细过程)

详细到啰嗦的程度,完全0基础都可完成。

m0_56283131的博客 4万+

Faster Planner——Kinodynamic Astar详解

实际成本和启发式成本 实际成本 Actual Cost   每条轨迹的真实代价函数定义如下: J(T)=∫0T∥u(t)∥2dt+ρT \mathcal{J}(T)=\int_{0}^{T}\|\mathbf{u}(t)\|^{2} d t+\rho T J(T)=∫0T​∥u(t)∥2dt+ρT 离散形式下: 启发成本 Heuristic Cost pμ∗(t)=16αμt3+12βμt2+vμc+pμc=pμc+vμc+T2∗((2∗vμc−2∗vμg)/(2∗T)−(6∗pμc−6∗pμg+6∗T∗v

漫长IT路 4831

详解二叉树的遍历

概述 二叉树的遍历是一个很常见的问题。二叉树的遍历方式主要有:先序遍历、中序遍历、后序遍历、层次遍历。先序、中序、后序其实指的是父节点被访问的次序。若在遍历过程中,父节点先于它的子节点被访问,就是先序遍历;父节点被访问的次序位于左右孩子节点之间,就是中序遍历;访问完左右孩子节点之后再访问父节点,就是后序遍历。不论是先序遍历、中序遍历还是后序遍历,左右孩子节点的相对访问次序是不变的,总是先访问左孩子...

supermouse的博客 1万+

保姆级教程:用Python+OpenCV搞定Orbbec Gemini深度与彩色流对齐(附完整代码)

本文提供了一份详细的Orbbec Gemini深度与彩色流对齐教程,涵盖从环境配置到完整代码实现的每一步。通过解析深度流对齐原理,对比不同对齐模式,并提供工业级应用中的问题排查方法,帮助开发者快速掌握Orbbec Gemini相机的使用技巧。文章还包含进阶应用如点云生成与三维重建的实战代码。

weixin_29090917的博客 470

MFRC522防冲突机制详解:当两张IC卡同时靠近读写器,会发生什么?

本文深入解析了MFRC522芯片在多张IC卡同时靠近RFID读写器时的防冲突机制,重点介绍了二叉树搜索算法在比特级的实现原理。通过详细的寄存器配置优化和实际工程案例,展示了如何有效解决信号碰撞问题,提升多卡场景下的读写性能。

weixin_29191669的博客 428

数据结构|二叉树的三种遍历方式,你掌握了几种?

本期讲解二叉树的三种遍历方式:前序遍历、中序遍历、后序遍历的详细讲解,图文并茂通俗易懂。

我的主页 1万+

解锁 STP 与 SOLIDWORKS 转换密码:工具及迪威在线转换秘籍

STP 文件能够完整地记录 3D 模型的几何形状、尺寸、公差、材料属性等丰富信息,无论是简单的机械零件,还是复杂的装配体,都能精准呈现。而在线转换以迪威模型为例,凭借便捷性、高效性和安全性,为广大 3D 专业技术人员和学生党在无需安装额外软件的情况下,轻松实现格式转换提供了有力支持。在实际工作和学习中,可根据自身具体情况灵活选择合适的转换方式,以确保 3D 设计工作流程的顺畅进行,让创意在不同格式间自由流动并绽放光彩。在 3D 设计与建模的广袤世界里,不同格式文件间的转换常常是连接创意与实现的关键桥梁。

技术说明博主 3444

一文弄懂二叉树的三种遍历方式

关注公众号:高性能架构探索。后台回复【资料】,可以免费领取 俗话说:学如逆水行舟,不进则退;心似平原走马,易放难收。这句话对程序员而言,体会更深。这行已经越来越卷了,时刻准备着,????。 二叉树,在面试中,已是必备的开胃菜。而在二叉树相关的面试题目中,遍历更是常考题目。本文将从二叉树的遍历角度入手,从递归和非递归角度来分析和讲解二叉树的遍历。 遍历 二叉树的遍历是指从根节点出发,按照某种次序依次访问二叉树中的所有节点,使每个节点被且仅被访问一次。 二叉树的遍历,有先序遍历、中序遍历以

高性能架构探索 2万+

Python xlwings报错解决:从‘NoneType‘到完美运行WPS表格的完整指南

本文深入解析了使用Python xlwings库自动化WPS表格时遇到的经典'NoneType'报错(AttributeError: 'NoneType' object has no attribute 'apps')的根源与解决方案。核心在于pywin32版本与WPS的兼容性问题,文章提供了从版本降级、依赖管理到构建健壮自动化环境的完整实战指南,帮助开发者彻底解决兼容性难题,实现稳定运行。

n4o5p6q7r的博客 303

[LaTeX] 使用natbib宏包实现参考文献的“作者-年份”引用格式及常见编译错误排查

本文详细介绍了在LaTeX中使用natbib宏包实现参考文献“作者-年份”引用格式的完整流程。从宏包配置、.bib文件准备到标准编译步骤,重点解析了常见的“Bibliography not compatible with author-year”错误成因,并提供了彻底清理辅助文件等解决方案,帮助用户高效排版符合学术规范的参考文献。

moon9的博客 481

二叉树的常用遍历方法

按照访问根节点——左子树——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树。:按照访问左子树——右子树——根节点的方式遍历这棵树,而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树。:按照访问左子树——根节点——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候我们按照同样的方式遍历,直到遍历完整棵树。树的遍历除了使用递归的方法,通常的还有迭代和Morris遍历,详细的请看另一篇文章。除了递归还可以用一个栈去维护。

FFNCL的博客 284

多模态论文笔记——VQ-VAE和VQ-VAE-2

本文详细介绍VQ-VAE和VQ-VAE-2的原理和训练过程,为后面的dVAE在DALLE中的使用打下坚实的基础。

haopinglianlian的博客 3299

二叉树的遍历和构建

给定两种遍历顺序,构建一个二叉树,前提是。二叉树常用遍历方式有三种。

2301_77668644的博客 189

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

二叉树遍历问题

二叉树的遍历 一、遍历方法 三种遍历方法,很好记,什么时候访问根节点就叫什么方法。如:先序遍历,肯定就是先访问根节点;中序遍历,就是中间访问根节点;后序遍历就是最后访问根节点。 1、先序遍历:首先访问根节点,然后先序遍历左子树,最后先序遍历右子树 2、中序遍历:首先中序遍历左子树,然后访问根节点,最后中序遍历右子树 3、后序遍历:首先后序...

weixin_34277853的博客 150

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

二叉树遍历的几种常见方法

https://blog.youkuaiyun.com/xxxxxxxx00772299/article/details/109318495/ 二叉树的遍历方法 一.二叉树分类: 完全二叉树 满二叉树 扩充二叉树 平衡二叉树 二.二叉树的四种遍历方式: 前序遍历(先根,再左,最后右) 中序遍历(先左,再根,最后右) 后序遍历(先左,再右,最后根) 层次遍历(说不清) 1.递归遍历 (1)前序遍历 遍历方法:先根节点,再左节点,最后右节点。 实现代码: /*声明结点TreeNode

yygr的博客 2214

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

遍历二叉树

遍历二叉树二叉树是由3个基本单元组成的:根结点、左子树和右子树。 若限定先左后右的顺序,则遍历二叉树只有三种情况分别称为先(根)序遍历、中(根)序遍历和后(根)序遍历。 先序遍历二叉树的操作定义为: 若二叉树为空,则空操作;否则 访问根结点; 先序遍历左子树; 先序遍历右子树。 中序遍历二叉树的操作定义为: 若二叉树为空,则空操作;否则 中序遍历左子树; 访问根结点; 中序遍历右子树。 后

Mazhitaoooo 584

二叉树的创建及遍历方法

在这里我们发现,我们每次存储时,基本上都是按照从上到下,从左到右的方式进行存储的,所以,我们此处存储数据时,可以先把根节点下面的左子树先存放完成,再存放右子树即可实现数据存储,并且,我们存放玩上一个数据之后的每一个节点都可以看做是一个根节点。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左孩子树和右孩子树组成的非空树;按照一般的存储逻辑,我们一般存储都是按照如下编号逐个存储,但是这样的存储方式不太适用于我们的链式存储,因此,这里我们需要使用到递归存储。......

m0_45901455的博客 4万+

二叉树中序遍历的三种方法

二叉树是一种重要的数据结构,对于二叉树的遍历也很重要。这里通过三种方法简单介绍一下二叉树的中序遍历。中序遍历就是先遍历二叉树的左子树,然后遍历根节点,最后遍历右子树。例如下面的二叉树,中序遍历的结果如下:[5,10,6,15,2]对于中序遍历,直观上的结果就是将二叉树所有节点投影到下面的一条直线上,得到的顺序就是二叉树的中序遍历结果。1、递归法递归方法是最容易想到的方法。递归调用遍历方法先遍历左子

Valineliu 12万+

图解二叉树及二叉树遍历

二叉树及二叉树遍历 完全二叉树 二叉树的遍历 遍历的性质 1、完全二叉树 对于一棵具有n个节点的二叉树(按层序编号),如果编号为i的节点与同样深度的满二叉树中编号为i的节点在二叉树的位置完全相同,则为完全二叉树。 换句话来说,如果每个节点按照满二叉树的结构逐层顺序进行编号,如果编号出现编号空挡,就说明不是完全二叉树,否则就是。如下图所示:左边二叉树按照完全二叉树进行编号,出现了10号的空挡,右边

xiaotan2011929的博客 2万+

二叉树的中序遍历(三种方法)

本文详细介绍了二叉树的三种遍历方法(递归,迭代,Morris),每一种遍历方式都有保姆级的思路讲解,还有完整代码(带有注释),还不赶紧点进来学习!!!

yourgrandfather_的博客 5184

遍历二叉树的神级方法-Morris遍历【建议收藏】

在前面,我们简单提及过二叉树的遍历方式,有递归和非递归两个版本的遍历。仔细想一想,不管是递归的,还是非递归的遍历,两种版本的遍历都是需要耗费大量的、额外的空间。比如当我们二叉树的高度有100层,那么递归时,系统就会一直压栈,一直要压入100次遍历的递归函数,因为此处的空间复杂度是跟这可二叉树的高度相关的。所以有人就在想,有没有什么方式,能够使这个空间复杂度再压缩一点呢? 前期文章:二叉树的非递归遍历 本期文章源码:GitHub 有,肯定是有的。那就是今天的主题:Morris遍历。这种思想就能使二叉树的遍历

x0919的博客 2509

二叉树的遍历及根据遍历反推树的方法详解

二叉树的遍历及根据遍历构建二叉树的方法 详解 一、前导-关于树的定义 森林(forest):每个连通分量(连通块)都是树的图。按照定义,一棵树也是森林。 生成树(spanning tree):一个连通无向图的生成子图,同时要求是树。也即在图的边集中选择 n−1n - 1n−1 条,将所有顶点连通。 结点的深度(depth):到根结点的路径上的边数。 树的高度(height):所有结点的深度的最大值。 无根树的叶结点(leaf node):度数不超过 111 的结点。 有根树的叶结点(

HeartFireY的博客 4880

二叉树三种遍历方式的六种实现方法

一、基本概念 每个结点最多有两棵子树,左子树和右子树,次序不可以颠倒。 性质: 1、非空二叉树的第n层上至多有2^(n-1)个元素。 2、深度为h的二叉树至多有2^h-1个结点。 3、对任何一棵二叉树T,如果其终端结点数(即叶子结点数)为n0,度为2的结点数为n2,则n0 = n2 + 1。 满二叉树:所有终端都在同一层次,且非终端结点的度数为2。

算法改变人生 2万+
上一篇: BFS与DFS套路总结
下一篇: 常见的位操作及其应用
vcjmhg
博客等级 码龄11年 27粉丝 94原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值