二叉树后序遍历算法多种实现傻傻分不清楚

致力于C、C++、Java、Kotlin、Android、Shell、JavaScript、TypeScript、Python等编程技术的技巧经验分享。

若作品对您有帮助,请关注、分享、点赞、收藏、在看、喜欢。您的支持是我们为您提供帮助的最大动力。


1.介绍
二叉树的后序遍历是一种遍历二叉树的策略,按照"左子树-》右子树-》根节点"的顺序访问节点的子树或根节点。具体来说,后序遍历首先访问左子树,然后访问右子树,最后访问根节点。
这种遍历方式在编程中可以通过递归或非递归的方式进行实现。
通常来说,递归算法较容易理解,但可能会造成栈溢出,而非递归算法较难理解。
以下用代码实现后序遍历。


2.代码
以下以Java编程语言为例。
1)二叉树节点的数据结构定义如下:

class TreeNode {
    int value;
    TreeNode left;
    TreeNode right;
    TreeNode(int value) {
        this.value = value;
    }
}

2)后序遍历递归算法代码

public void postOrderTraversalRecursive(TreeNode root){
        //若root节点为空,则子遍历完成
        if(null==root){
            return ;
        }
        //先递归遍历左子树
        postOrderTraversalRecursive(root.left);
        //再递归遍历右子树
        postOrderTraversalRecursive(root.right);
        //最后访问根节点
        System.out.println(root.value);
}

3)后序遍历非递归算法代码(单栈法)
可以使用栈来模拟递归过程。此例只用到了一个栈,所以叫做单栈法。
后序遍历与前序遍历和中序遍历存在差异。即我们在访问左子树之后需要访问右子树,然后才能再访问根节点,所以我们的根节点不能在访问左子树之后出栈,而是需要继续访问右子树,当我们右子树访问完成之后再出栈。

public void postOrderTraversalNonRecursive(TreeNode root)
{
    //存储遍历过程中的需要继续处理的临时节点
    Stack<TreeNode> stack = new Stack<>();
    //保存临时根节点,从root开始
    TreeNode node =root;
    //保存上次访问的节点,从root开始
    TreeNode lastVisit = root;
    //临时节点不为空或者栈不为空时需要继续处理
    while(null != node || !stack.empty())
    {
        while(null != node){
            //存储临时节点到栈中
            stack.push(node);
            //继续遍历左子树
            node = node.left;
        }
        //查看当前栈顶元素
        node = stack.peek();
        //如果当前栈顶元素的右子树为空,或者右子树已经被访问,则说明左右节点都访问完成了
        //则可以直接输出当前节点的值
        if(null == node.right || node.right==lastVisit){
            //左子树与右子树都访问完成后输出当前根节点的值
            System.out.println(node.value+" ");
            //当前节点已处理完成,从栈中弹出,继续下一轮遍历
            stack.pop();
            //更新上次访问的节点
            lastVisit=node;
            //左子树右子树根节点都访问完毕后,将临时节点置空,从而从栈中处理下一个节点
            node=null;
        }else{
            //右子树尚未被访问,则继续遍历右子树
            node=node.right;
        }
    }
}

4)后序遍历非递归算法代码(双栈法)
由于后序遍历的输出顺序是左->右->根,倒过来就是根->右->左。因此利用栈(先进后出FILO,与正常顺序是反的)的性质,只需要按照根->右->左的访问顺序访问一次,并存入栈中,最后从栈顶输出所有栈节点就可以了。
算法需要两个栈,一个是正常遍历需要的栈,一个是存储倒过来的元素的栈,所以也叫双栈法。

public static void postOrderTraversalNonRecursive2Stack(TreeNode root) {
   //后序遍历中存储正常访问顺序的栈
   Stack<TreeNode> stack = new Stack<TreeNode>();
   //后序遍历中存储逆向访问顺序的栈
   Stack<TreeNode> output = new Stack<TreeNode>();
   TreeNode node = root;
   //判断是否还有节点需要处理
   while (null != node || !stack.isEmpty()) {
       if (null != node) {
           //先访问根节点,压入栈中
           stack.push(node);
           output.push(node);
           //再访问右子节点
           node = node.right;
       } else {
           //再访问左子节点
           node = stack.pop();
           node = node.left;
       }
   }

    //从栈顶开始输出栈里元素的值,即输出正常访问顺序栈stack的倒序结果output栈,即为最终结果
   while (output.size() > 0) {
       TreeNode n = output.pop();
       System.out.print(n.value + " ");
   }
}

5)后序遍历非递归算法代码(Stack+Deque,即栈+双向队列法)
算法的数据结构里,一个存储正常遍历需要的栈,一个存储最终输出的元素双端队列列表,所以也叫栈+双向队列法。

public List<TreeNode> postOrderTraversalNonRecursiveStackDeque(TreeNode root) {
     //保存计算出的最终结果列表
     LinkedList<TreeNode> result = new LinkedList<>();
     //若root节点为空,则遍历完成
     if (null == root) {
        return result;
     }
     //后序遍历中存储正常访问顺序的栈
     Stack<TreeNode> stack = new Stack<>();
     //压入根节点到栈中
     stack.push(root);
     //存储当前节点
     TreeNode curNode;
     //若栈中有数据,则继续处理
     while(!stack.isEmpty()) {
         //获取当前栈顶元素
         curNode = stack.pop();
         //将栈顶元素插入到结果列表LinkedList的头部
         result.addFirst(curNode.value);
         if (null != curNode.left) {
             //压入左子节点到栈中
             stack.push(curNode.left);
         }
         if (null != curNode.right) {
             //压入右子节点到栈中
             stack.push(curNode.right);
         }
     }
     return result;
}


 


若作品对您有帮助,请关注、分享、点赞、收藏、在看、喜欢。您的支持是我们为您提供帮助的最大动力。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

运行v3+ts+vite+eslint碰到的问题集合

1、问题&#xff1a;提示Missing semicolon semi&#xff08;缺少分号&#xff09; 解决&#xff1a;对比其他ts代码&#xff0c;发现在orderDetail后少了分号&#xff0c;加上去之后就可以了。好严格&#xff01;&#xff01;&#xff01; 2、问题&#xff1a;The template…

idea开发 java web 疫情信息查询系统bootstrap框架web结构java编程计算机网页接口查询

一、源码特点 java 疫情信息查询系统是一套完善的完整信息系统&#xff0c;结合java web开发和bootstrap UI框架完成本系统 &#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 前段主要技术 css j…

PP-Structure 文档分析

本文接着上一篇文章&#xff1a;PaddleOCR环境搭建、模型训练、推理、部署全流程&#xff08;Ubuntu系统&#xff09;-CSDN博客 主要包括以下几种&#xff1a; PP-Structure 文档分析 --官方地址 1.1版面分析和表格识别1.2版面恢复1.3关键信息抽取 1. 简介 PP-Structu…

云手机提供私域流量变现方案

当今数字营销领域&#xff0c;私域流量是一座巨大的金矿&#xff0c;然而并非人人能够轻易挖掘。一家营销公司面临着利用社交、社区、自媒体等应用积累私域流量&#xff0c;并通过销售产品、推送广告等方式实现流量变现的挑战与困境。本文将详细介绍这家公司是如何通过云手机&a…

填字母游戏【蓝桥杯】/博弈+dfs

填字母游戏 博弈dfs #include<iostream> #include<map> using namespace std; //要用map存储已经处理过的字符串不然会超时 map<string,int> m; //dfs返回的就是结果 int dfs(string s) {//剪枝if(m.find(s)!m.end()) return m[s];//找到LOL代表输了if(s.fi…

[STL-list]介绍、与vector的对比、模拟实现的迭代器问题

一、list使用介绍 list的底层是带头双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前一个元素和后一个元素。与其他的序列式容器相比(array&#xff0c;vector&#xff0c;deque)&#xff0c;list通常在任意位置进行…

Kubernetes(k8s)监控与报警:Prometheus + Grafana + Alertmanager(超详细)

Kubernetes&#xff08;k8s&#xff09;监控与报警&#xff1a;Prometheus Grafana Alertmanager&#xff08;超详细&#xff09; 1、部署环境2、基本概念简介2.1、Prometheus简介2.2、Grafana简介2.3、Alertmanager简介2.4、Prometheus GrafanaAlertmanager监控架构 3、Pro…

品牌发言稿怎么写?纯干货

品牌发言稿的重要性不言而喻&#xff0c;它不仅代表着品牌形象&#xff0c;更是沟通品牌与消费者、合作伙伴的桥梁。如何撰写一篇高质量的品牌发言稿&#xff0c;成为许多品牌关注的焦点。伯乐网络传媒十多年文案撰写经验&#xff0c;今天就来给大家讲一讲。 一、品牌发言稿的组…

关系(三)利用python绘制相关矩阵图

关系&#xff08;三&#xff09;利用python绘制相关矩阵图 相关矩阵图&#xff08;Correlogram&#xff09;简介 相关矩阵图既可以分析每对变量之间的相关性&#xff0c;也可以分析单变量的分布情况。相关性以散点图的形式可视化&#xff0c;对角线用直方图/密度图表示每个变量…

面试字节被挂了

分享一个面试字节的经历。 1、面试过程 一面&#xff1a;上来就直接"做个题吧"&#xff0c;做完之后&#xff0c;对着简历上一个项目聊&#xff0c;一直聊到最后&#xff0c;还算比较正常。 二面&#xff1a;做自我介绍&#xff0c;花几分钟聊了一个项目&#xff…

Notepad++软件安装及配置说明

Notepad是 Windows操作系统下的一套文本编辑器&#xff0c;有完整的中文化接口及支持多国语言编写的功能。 Notepad功能比 Windows自带记事本强大&#xff0c;除了可以用来制作一般的纯文字说明文件&#xff0c;也十分适合编写计算机程序代码。Notepad不但可以显示行号&#xf…

精酿啤酒的未来:创新与传统的碰撞

随着精酿啤酒的兴起&#xff0c;越来越多的人开始关注这一领域的发展趋势。精酿啤酒作为啤酒中的一种新兴类别&#xff0c;其未来发展将受到创新与传统的碰撞和影响。在这其中&#xff0c;Fendi Club啤酒屋作为精酿啤酒的代表性场所&#xff0c;将继续发挥其重要的作用。 首先&…

windows10系统下TP-LINK万兆网卡属性配置高级说明

文章目录 打开配置属性说明ARP Offload&#xff1a;ARP地址解析协议卸载Downshift retries:降档重试次数Energy-Efficient Ethernet:高能效以太网Flow Control:流量控制Interrupt Moderation:中断调整Interrupt Moderation Rate:中断调节率IPv4 Checksum Offload:IPv4校验和卸载…

好看的短袖品牌有哪些?不会穿搭的男生有这几件短袖就够了

很多朋友都经常跟我说&#xff0c;自己买回来的衣服要么就是太长要么就是太短&#xff0c;甚至还有一些质量很差的衣服。而主要的原因就是目前市面上有太多未经过细节优化的衣裤&#xff0c;同时鱼龙混杂的市场也让大家十分容易选择到这类衣服。 而最近天气也逐渐转热&#xf…

java算法day46 | 动态规划part08 ● 139.单词拆分 ● 关于多重背包,你该了解这些! ● 背包问题总结篇!

139.单词拆分 完全背包问题&#xff0c;只不过装入背包时需要附加一个判断条件。 class Solution {public boolean wordBreak(String s, List<String> wordDict) {boolean[] dpnew boolean[s.length()1];dp[0]true;for(int j1;j<s.length();j){for(int i0;i<wordD…

【深度学习】最强算法之:深度Q网络(DQN)

深度Q网络 1、引言2、深度Q网络2.1 定义2.2 原理2.3 实现方式2.4 算法公式2.5 代码示例 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c; 马上清明小长假了&#xff0c; 你这准备去哪里玩啊&#xff1f; 小鱼&#xff1a;哪也不去&#xff0c;在家待着 小屌丝&#xff1a…

Java 开发篇+一个简单的数据库管理系统ZDB

说明&#xff1a;本文供数据库爱好者和初级开发人员学习使用 标签&#xff1a;数据库管理系统、RDBMS、Java小程序、Java、Java程序 系统&#xff1a;Windows 11 x86 CPU &#xff1a;Intel IDE &#xff1a;IntelliJ IDEA Community Edition 2024 语言&#xff1a;Java语言 标…

“AI+信创”两翼齐飞,实在智能全面加速自主可控实在智能RPA

近日&#xff0c;实在智能牵手华为昇腾、摩尔线程在信创领域展开紧密合作&#xff0c;共同加速推进AI和信创产业创新发展。 华为昇腾与实在智能达成昇腾原生大模型联合创新合作&#xff0c;基于华为昇腾AI自主创新软硬件平台全栈技术、实在智能自研RPA基础大模型解决方案能力&a…

简单好用高效的视频补帧软件:Squirrel-RIFE

Squirrel-RIFE&#xff0c;轻松实现高效补帧&#xff0c;让您的视频画面瞬间流畅升级&#xff01;- 精选真开源&#xff0c;释放新价值。 概览 在观看视频内容的过程中&#xff0c;尤其是面对复杂多变的动画场景或高速运动镜头时&#xff0c;观众时常会遭遇视频帧率不足所引发…

算法中的二阶差分

众所周知&#xff0c;在往区间的每一个数都加上一个相同的数k&#xff0c;进行n次后会得到一个新的数列&#xff0c;如果每次加都循环区间挨个数加上k&#xff0c;这样时间复杂度无疑是O(n^2)&#xff0c;很高。这时可以采用一阶差分就可解决&#xff0c;这里默认会一阶差分&am…