Java二叉树三序遍历的非递归实现

news2024/11/20 18:41:52

目录

零、本文中模拟实现的二叉树源码

一、前序遍历的非递归实现

1.代码示例:

2.与递归算法的比对演示:

二、中序遍历的非递归实现

1.代码示例:

2.与递归算法的比对演示:

三、后序遍历的非递归实现

1.代码示例:

2.与递归算法的比对演示:


     二叉树由于结构的递归特性(即一棵树的子树仍然为一棵树),所以其大部分算法都是以递归形式进行的。本文将从非递归的角度与思路出发,实现java二叉树的三序遍历(前序遍历,中序遍历,后序遍历)。

零、本文中模拟实现的二叉树源码

class TreeNode {
    public char val;
    public TreeNode left;
    public TreeNode right;

    //TreeNode的构造方法
    public TreeNode(char val) {
        this.val = val;
    }
}

class MyBinaryTree {
     //人为拼接构造一颗二叉树的方法
     public TreeNode creatTree() {
         TreeNode A = new TreeNode('A');
         TreeNode B = new TreeNode('B');
         TreeNode C = new TreeNode('C');
         TreeNode D = new TreeNode('D');
         TreeNode E = new TreeNode('E');
         TreeNode F = new TreeNode('F');
         TreeNode G = new TreeNode('G');
         TreeNode H = new TreeNode('H');
         TreeNode I = new TreeNode('I');
         A.left = B;
         A.right = C;
         B.left = D;
         B.right = E;
         C.left = F;
         C.right = G;
         E.right = H;
         F.left = I;
         return A;//返回根节点A
     }

     //查找二叉树中是否包含值为key的节点的方法
     public TreeNode find(TreeNode root, char key) {
         //空节点返回空
         if (root == null) {
             return null;
         }
         //找到key值节点则返回
         if (root.val == key) {
             return root;
         }
         //递归左子树
         TreeNode leftVal = find(root.left, key);
         if (leftVal != null) {
             return leftVal;
         }
         //递归右子树
         TreeNode rightVal = find(root.right, key);
         if (rightVal != null) {
             return rightVal;
         }
         //程序全部运行结束说明没有招到值为key的节点
         return null;
     }

     //前序遍历方法
     public void preOrder(TreeNode root) {
         //空节点返回
         if (root == null) {
             return;
         }
         //打印根节点
         System.out.print(root.val + " ");
         //递归左子树
         preOrder(root.left);
         //递归右子树
         preOrder(root.right);

     }

     //中序遍历方法
     public void inOrder(TreeNode root) {
         //空节点返回
         if (root == null) {
             return;
         }
         //递归左子树
         inOrder(root.left);
         //打印根节点
         System.out.print(root.val + " ");
         //递归右子树
         inOrder(root.right);

     }

     //后序遍历方法
     public void postOrder(TreeNode root) {
         //空节点返回
         if (root == null) {
             return;
         }
         //递归左子树
         postOrder(root.left);
         //递归右子树
         postOrder(root.right);
         //打印根节点
         System.out.print(root.val + " ");

     }

     //获取树中的节点个数的方法
     public int getSize(TreeNode root) {
         //空节点返回0
         if (root == null) {
             return 0;
         }
         //递归左子树和右子树(+1为根节点个数)
         int size = 1 + getSize(root.left) + getSize(root.right);
         return size;
     }

     //获取二叉树中叶子节点个数的方法
     public int getLeafNodeCount(TreeNode root) {
         //空节点返回0
         if (root == null) {
             return 0;
         }
         //叶子节点返回1
         if (root.left == null && root.right == null) {
             return 1;
         }
         //递归左子树和右子树
         int count = getLeafNodeCount(root.left) + getLeafNodeCount(root.right);
         return count;
     }

     //获取第k层(根节点层数为0)的节点个数的方法
     public int getKthLevelNodeCount(TreeNode root, int k) {
         //空节点返回0
         if (root == null) {
             return 0;
         } else if (k == 0) {
             //本层节点返回1
             return 1;
         }
         //递归左子树和右子树
         return getKthLevelNodeCount(root.left, k - 1) + getKthLevelNodeCount(root.right, k);

     }

     //获取二叉树的深度的方法
     public int getHight(TreeNode root) {
         //空节点返回-1
         if (root == null) {
             return -1;
         }
         //递归左子树
         int leftHeight = getHight(root.left);
         //递归右子树
         int rightHeight = getHight(root.right);
         //返回其中最大值
         return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
     }
 }

一、前序遍历的非递归实现

     由二叉树前序递归遍历的特点可知,在前序遍历中整体为自下而上的遍历顺序,并且输出根节点为最高优先级,向左子树递归为次高优先级,向右子树遍历为最低优先级(即根节点不为空优先输出根节点,否则左子树不为空优先向左子树递归,否则最后向右子树递归)。所以我们可以通过借助栈来模拟自下而上的遍历顺序以及非递归的算法来模拟递归中优先级的思路实现前序遍历。

1.代码示例:

public class PreOrderNot {
    //非递归方式实现前序遍历的方法
    public void preOrderNot(TreeNode root){
        //创建一个新的栈
        Stack<TreeNode>stack=new Stack<>();
        //用cur记录当前遍历节点
        TreeNode cur=root;
        //根据先序遍历从下到上的顺序可知,若cur不为空或者栈不为空循环继续,使得cur从下至上遍历
        while(cur!=null||!stack.isEmpty()){
            while(cur!=null){
                stack.push(cur);
                //输出根节点值为最高优先级
                System.out.print(cur.val+" ");
                //向左子树遍历为次高优先级
                cur=cur.left;
            }
            //节点此时已打印完毕,弹出此节点,用top记录,以便向右子树遍历
            TreeNode top=stack.pop();
            //向右子树遍历为最低优先级
            cur=top.right;
        }

    }
    //main方法用于测试代码
    public static void main(String[] args) {
        MyBinaryTree myBinaryTree=new MyBinaryTree();
        PreOrderNot preOrderNot=new PreOrderNot();
        //人为创建一棵二叉树
        TreeNode root=myBinaryTree.creatTree();

        //递归方法实现前序遍历演示
        System.out.print("递归实现:  ");
        myBinaryTree.preOrder(root);
        System.out.println();
        System.out.println("*****************************");
        System.out.print("非递归实现:");
        preOrderNot.preOrderNot(root);
    }
}

2.与递归算法的比对演示:

测试代码为main方法中代码,结果如下: 

二、中序遍历的非递归实现

     同前序遍历,由二叉树中序递归遍历的特点可知,在中序遍历中整体为自下而上的遍历顺序,并且向左子树递归为最高优先级,输出根节点为次高优先级,向右子树遍历为最低优先级(即左子树不为空优先向左子树递归,否则根节点不为空优先输出根节点,否则最后向右子树递归)。所以我们可以通过借助栈来模拟自下而上的遍历顺序以及非递归的算法来模拟递归中优先级的思路实现中序遍历。

1.代码示例:

public class InOrderNot {
    //非递归方式实现中序遍历的方法
    public void inOrderNot(TreeNode root){
        //创建一个新的栈
        Stack<TreeNode>stack=new Stack<>();
        //用cur记录当前遍历节点
        TreeNode cur=root;
        //根据先序遍历从下到上的顺序可知,若cur不为空或者栈不为空循环继续,使得cur从下至上遍历
        while(cur!=null||!stack.isEmpty()){
            while(cur!=null){
                stack.push(cur);
                //向左子树遍历为最高优先级
                cur=cur.left;
            }
            //弹出此节点,用top记录,以便向打印此节点和右子树遍历
            TreeNode top=stack.pop();
            //输出根节点值为次高优先级
            System.out.print(top.val+" ");
            //向右子树遍历为最低优先级
            cur=top.right;
        }

    }
    //main方法用于测试代码
    public static void main(String[] args) {
        MyBinaryTree myBinaryTree=new MyBinaryTree();
        InOrderNot inOrderNot=new InOrderNot();
        //人为创建一棵二叉树
        TreeNode root=myBinaryTree.creatTree();

        //递归方法实现中序遍历演示
        System.out.print("递归实现:  ");
        myBinaryTree.inOrder(root);
        System.out.println();
        System.out.println("*****************************");
        System.out.print("非递归实现:");
        inOrderNot.inOrderNot(root);
    }
}

2.与递归算法的比对演示:

三、后序遍历的非递归实现

     同前序遍历与中序遍历,由二叉树后序递归遍历的特点可知,在后序遍历中整体为自下而上的遍历顺序,并且向左子树递归为最高优先级,向右子树遍历为次高优先级,输出根节点为最低优先级(即左子树不为空优先向左子树递归,否则右子树不为空优先向右子树递归,否则最后输出根节点)。所以我们可以通过借助栈来模拟自下而上的遍历顺序以及非递归的算法来模拟递归中优先级的思路实现后序遍历。

1.代码示例:

public class PostOrderNot {
    //通过非递归方式实现后序遍历的方法
    public void postOrderNot(TreeNode root){
        //创建一个新的栈
        Stack<TreeNode>stack=new Stack<>();
        //用cur记录当前遍历节点
        TreeNode cur=root;
        //用prev记录上一个已经输出过的节点,避免进入死循环
        TreeNode prev=null;
        //根据先序遍历从下到上的顺序可知,若cur不为空或者栈不为空循环继续,使得cur从下至上遍历
        while(cur!=null||!stack.isEmpty()){
            while(cur!=null){
                stack.push(cur);
                //向左子树遍历为最高优先级
                cur=cur.left;
            }
            //获取此节点,用top记录,(不可像前中序遍历那样弹出,因为输出根节点值为最低优先级,若此时就弹出则无法再输出)以便右子树遍历和打印此节点
            TreeNode top=stack.peek();

            if(top.right!=null&&top.right!=prev){
                //向右子树遍历为次高优先级
                cur=top.right;
            }else{
                //输出根节点值为最低优先级
                System.out.print(top.val+" ");
                //此节点已经输出,将其弹出
                stack.pop();
                //用prev记录上一个已经输出过的节点,避免进入死循环
                prev=top;
            }
        }
    }
    //main方法用于测试代码
    public static void main(String[] args) {
        MyBinaryTree myBinaryTree=new MyBinaryTree();
        PostOrderNot postOrderNot=new PostOrderNot();
        //人为创捷一棵树
        TreeNode root=myBinaryTree.creatTree();

        //递归方法实现后序遍历演示
        System.out.print("递归实现:  ");
        myBinaryTree.postOrder(root);
        System.out.println();
        System.out.println("*****************************");
        System.out.print("非递归实现:");
        postOrderNot.postOrderNot(root);
    }
}

2.与递归算法的比对演示:

以上便是Java二叉树三序遍历的非递归实现的全部内容,如有不当,敬请斧正!

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

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

相关文章

VScode连接算力云服务器

打开VScode,找到插件市场,搜索Remote - SSH 下载插件Remote - SSH之后会出现下面这个,直接点击。 将下面这个恒源云租服务器的登陆指令 复制到下面之中,enter确认。 然后点第一个 然后点这个 复制粘贴这个云服务器的密码,(它不会显示,但你已经粘贴了)

Paddlenlp测试

1、环境安装 使用华为云euleros操作系统&#xff0c;python版本3.9.5&#xff0c;CPU无GPU服务器&#xff1a; &#xff08;1&#xff09;pip3 install setuptools_scm -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com &#xff08;2&#xf…

js 替换json中的转义字符 \

例如有以下字符串 "\"{\\\"account\\\":\\\"66\\\",\\\"name\\\":\\\"66\\\"}\"" 想得到如下字符串 {"account":"66","name":"66"} 执行替换字符串 "\"{…

【科研绘图】记录一次论文结果复现

复现原论文中的图片是科研的基本功之一&#xff0c;它不仅验证了研究结果的可靠性&#xff0c;确保了科学工作的准确性和可重复性&#xff0c;还深刻地评估了方法的有效性&#xff0c;体现了对原始研究的尊重和对科学过程的严谨态度。这个过程不仅提高了研究的透明度&#xff0…

科普文:docker基础概念、软件安装和常用命令

docker基本概念 一 容器的概念 1. 什么是容器&#xff1a;容器是在隔离的环境里面运行的一个进程&#xff0c;这个隔离的环境有自己的系统目录文件&#xff0c;有自己的ip地址&#xff0c;主机名等。也可以说&#xff1a;容器是一种轻量级虚拟化的技术。 2. 容器相对于kvm虚…

计算机组成原理--慕课网学习笔记

本文记录了学习慕课网课程【新版】计算机基础&#xff0c;计算机组成原理操作系统网络时的计算机组成原理篇的笔记&#xff0c;方便查阅复习使用 一、概述篇 1.1 计算机的发展历史 1&#xff09;计算机发展的四个阶段 ①第一个阶段&#xff1a;电子管计算机 背景&#xff1a…

一文掌握什么是时间序列?时间序列研究的核心任务?目前最强大的时序分析与建模工具和项目?

🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 什么是时间序列? 时间序列是一系列按照时间顺序排列的数据点,这些数据点通常是随时间连续变化的测量值。时间序列分析是统计学中专门用于解析时间顺序数据的一套技术,旨在识别数据中的模式、趋势、季节性波动及其他潜在…

计算机网络:构建联结的基础

目录 1. 网络拓扑结构 1.1 星型拓扑 1.2 环型拓扑 1.3 总线型拓扑 1.4 网状拓扑 2. 传输介质 2.1 双绞线 2.2 同轴电缆 2.3 光纤 2.4 无线电波 3. 协议栈模型 3.1 OSI模型 3.2 TCP/IP模型 4. 网络设备 4.1 交换机 4.2 路由器 4.3 网关 4.4 防火墙 5. IP地址…

Linux下Centos7中的gcc/g++

命为志存。 —— 朱熹 Linux中C/C翻译过程 1、样例介绍1、1、gcc版本过低不能编译成功1、2、编写 .cxx或.cc或.cpp代码(都是C) 2、程序的翻译过程2、1、条件编译(补充)2、2、语言历史 3、深入理解链接3、1、静态链接的使用场景 1、样例介绍 1、1、gcc版本过低不能编译成功 in…

QT vs2019编译报错LNK2019无法解析的外部符号

严重性 代码 说明 项目 文件 行 禁止显示状态 错误 LNK2019 无法解析的外部符号 "public: __cdecl Dialog_Setting::Dialog_Setting(class QWidget *)" (??0Dialog_SettingQEAAPEAVQWidgetZ)&#xff0c;函数 "public: __cdecl QtWid…

全感知、全覆盖、全智能的智慧快消开源了。

智慧快消视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。AI安全管理平台&…

0727,学什么学,周六就应该休息!!!!!

周六就应该休息&#xff0c;一天就忙了两小时也不是我的错喵 目录 UDP的小总结 01&#xff1a;使用select实现一个基于UDP的一对一即时聊天程序。 1.0 复读机服务器和树洞客户端 2.0 byby不了一点的敬业服务器&#xff01;&#xff01;&#xff01; 今天到此为止&#x…

Vue2.

vue2 模版语法 插值语法 标签体内容 指令语法 标签属性 v-bind: >> : 绑定 数据绑定 el与data的两种写法 理解MVVM模型 vue实例对象中的_proto_属性内 是 vue原型对象上的方法 数据代理 回顾object.defineproperty方法 数据代理定义&#xff1a; vue中的数据…

dify(docker)配置域名访问配置https

1. 要把证书放到 容器里面 放到nginx的目录里面 这个是在windows下 如果在Linux下 先上传到Linux服务器上然后复制到容器里面 docker-nginx-1 为容器的名字 2. 修改conf.d 里面的 default.conf 配置文件 把注释的代码放出来 3. 修改yaml文件 修改dify-main\docker下…

react中useReducer钩子函数的使用

1.代码展示 import { useReducer } from "react"// 1.定义reducer函数&#xff0c;根据不同action返回不同状态 function reducer(state, action) {console.log(state, action);switch (action.type) {case "INC":return state 1break;case "DEC&qu…

【黑科技】:Laravel 项目性能提升 20 倍

令人激动的黑科技&#xff1a;Laravel 项目性能提升 20 倍 这个项目能够在无需修改任何代码且无需第三方扩展的前提下&#xff0c;将你的 Laravel 项目性能提高 20 倍。它仅依赖于 PHP 原生的 pcntl、posix、fiber 和 sockets。 项目灵感 起因是看到官方发布的 PHP 8.1 更新…

CTF-NSSCTF[NISACTF 2022]

[NISACTF 2022]middlerce 考察&#xff1a;正则匹配回溯绕过 这里使用的是正则匹配的NIF匹配引擎,这个匹配引擎的原理是基于从后往前回溯的匹配机制 NIF匹配机制 当preg_match这个函数进行匹配时是匹配完后才根据匹配到与否来返回bool值 如果匹配到也要匹配完后才返回true,…

linux mysql 定时备份

1、创建备份文件夹 cd /homemkdir backup2、创建脚本文件 vim bkDatabaseName.sh加入以下内容&#xff08;/xp/server/mysql/bin/mysqldump是你的mysqldump备份命令&#xff0c;一般如果是正常安装的&#xff0c;可以直接用全局命令mysqldump&#xff0c;不用带前面的路径&am…

【前端 02】新浪新闻项目-初步使用CSS来排版

在今天的博文中&#xff0c;我们将围绕“新浪新闻”项目&#xff0c;深入探讨HTML和CSS在网页制作中的基础应用。通过具体实例&#xff0c;我们将学习如何设置图片、标题、超链接以及文本排版&#xff0c;同时了解CSS的引入方式和选择器优先级&#xff0c;以及视频和音频标签的…