java非递归实现之二叉树的前中后序遍历详解

Java非递归实现之二叉树的前中后序遍历详解

1、概述

在程序设计中,二叉树是一种常用的数据结构,而对二叉树进行遍历则是非常基础和重要的操作。二叉树的遍历分为三种:前序遍历、中序遍历和后序遍历。

常规的二叉树遍历算法使用递归完成,但是递归算法的效率比较低,同时深度过深还会导致调用栈溢出,因此我们可以采用非递归的方式来实现二叉树的遍历。

本文将通过Java代码,详细说明如何使用非递归的方式来实现二叉树的前、中、后序遍历。

2、前序遍历实现

前序遍历的顺序是:根节点、左子树、右子树。下面是非递归实现的前序遍历方法。

/**
 * 非递归前序遍历
 * @param root 二叉树的根节点
 */
public void preOrderTraversal(TreeNode root) {
    if (root == null) return;
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root); // 根节点入栈
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        System.out.print(node.val + " ");
        // 先将右子树入栈
        if (node.right != null) stack.push(node.right);
        // 再将左子树入栈
        if (node.left != null) stack.push(node.left);
    }
}

我们使用栈来模拟递归的过程,但是和递归不同的是,在入栈的时候,先将右子树入栈,然后再将左子树入栈,这是因为节点出栈的顺序是先左子树,然后右子树,最后根节点,使用这样的顺序保证了节点出栈的顺序符合前序遍历的规则。

例如,对于下面的二叉树:

         1
        / \
       2   3
      / \   \
     4   5   6

我们非递归前序遍历的结果是:1 2 4 5 3 6

3、中序遍历实现

中序遍历的顺序是:左子树、根节点、右子树。下面是非递归实现的中序遍历方法。

/**
 * 非递归中序遍历
 * @param root 二叉树的根节点
 */
public void inOrderTraversal(TreeNode root) {
    Stack<TreeNode> stack = new Stack<>();
    TreeNode cur = root;
    while (cur != null || !stack.isEmpty()) {
        while (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }
        TreeNode node = stack.pop();
        System.out.print(node.val + " ");
        cur = node.right;
    }
}

我们使用栈来模拟递归的过程,首先将根节点入栈,然后将当前节点设置为左子树,直到没有左子树了,此时节点出栈,然后将当前节点设置为右子树,再开始新一轮的遍历。

例如,对于下面的二叉树:

         1
        / \
       2   3
      / \   \
     4   5   6

我们非递归中序遍历的结果是:4 2 5 1 3 6

4、后序遍历实现

后序遍历的顺序是:左子树、右子树、根节点。下面是非递归实现的后序遍历方法。

/**
 * 非递归后序遍历
 * @param root 二叉树的根节点
 */
public void postOrderTraversal(TreeNode root) {
    if (root == null) return;
    Stack<TreeNode> stack1 = new Stack<>();
    Stack<TreeNode> stack2 = new Stack<>();
    stack1.push(root);
    while (!stack1.isEmpty()) {
        TreeNode node = stack1.pop();
        stack2.push(node);
        if (node.left != null) stack1.push(node.left);
        if (node.right != null) stack1.push(node.right);
    }
    while (!stack2.isEmpty()) {
        TreeNode node = stack2.pop();
        System.out.print(node.val + " ");
    }
}

我们使用两个栈来实现后序遍历,首先将根节点入栈1,然后将节点依次出栈放入栈2,同时将左右子树入栈1,当栈1为空时,栈2中的节点就是按照后序遍历的顺序排列的。

例如,对于下面的二叉树:

         1
        / \
       2   3
      / \   \
     4   5   6

我们非递归后续遍历的结果是:4 5 2 6 3 1

5、总结

使用非递归的方式实现二叉树的遍历操作,可以避免递归带来的调用栈过深的问题,提高算法的效率。本文介绍了使用Java代码实现二叉树的前序、中序、后序遍历的非递归方法,希望对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java非递归实现之二叉树的前中后序遍历详解 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • 通信网络 2G 3G 4G 和路由器2.4G 5G的区分和关系

    通信网络 2G 3G 4G 和路由器2.4G 5G的区分和关系 通信网络的发展历程 移动通信领域的发展是一个不断迭代更新的过程。从 1980 年代开始的 1G 网络,到 1990 年代的 2G 网络,再到 2000 年代的 3G 网络,以及近年来兴起的 4G 网络,每一代网络的诞生都标志着技术的进步和通信的便捷。 2G、3G 和 4G 网络的区别 2G 网络…

    其他 2023年3月28日
    00
  • Python类成员继承重写的实现

    Python类的继承和重写是面向对象编程的重要概念,实现类成员继承和重写可以提高代码的可复用性和可维护性,下面提供一份完整的攻略。 1. Python类的继承 在 Python 中,我们通过继承来实现类的复用,如果一个类需要复用另一个类中的属性和方法,可以通过继承的方式来实现。 在定义一个子类时,需要在类名的后面加上父类名,如下所示: class Paren…

    other 2023年6月27日
    00
  • vue全局引入scss(mixin)

    要在Vue中全局引入SCSS mixin,需要以下步骤: 1. 安装sass-loader和node-sass 在Vue项目中使用SCSS需要先安装sass-loader和node-sass两个依赖包。 npm install sass-loader node-sass -D 2. 在vue.config.js中配置 在Vue项目根目录下新建vue.conf…

    other 2023年6月27日
    00
  • Web端测试PHP代码函数覆盖率解决方案

    下面是详细的攻略: Web端测试PHP代码函数覆盖率解决方案 什么是函数覆盖率 函数覆盖率是一种测试代码质量的方法,它衡量了测试用例对于代码中各个函数执行路径的覆盖程度。 通常情况下,覆盖率的计算基于统计信息,可以具体分为语句覆盖率,分支覆盖率,路径覆盖率等。 测试工具选择 在PHP测试领域中,PHPUnit是比较流行的测试框架。而在测试覆盖率领域,PHPU…

    other 2023年6月26日
    00
  • web前端助手(fehelper)

    Web前端助手(fehelper)完整攻略 Web前端助手(fehelper)是一款Chrome浏览器插件,它提供了一系列实用前端开发具,包括页面元素查看、CSS样式查看、JS调试、JSON格式化、二维码生成等功能。本攻略将详细绍Web前端助手的安装、配置和使用方法,包括基本概念、安装配置和示例说明。 基本概念 Web前端助手(fehelper)是一款Chr…

    other 2023年5月6日
    00
  • 一文详解C语言操作符

    一文详解C语言操作符 C语言是一种被广泛使用的编程语言,在C语言中操作符起到了非常重要的作用。本文将详细介绍C语言中常用的操作符及其用法。 1. 算术操作符 算术操作符用于执行基本的数学运算,常见的算术操作符包括: 加号(+):用于执行加法运算。 减号(-):用于执行减法运算。 乘号(*):用于执行乘法运算。 除号(/):用于执行除法运算。 模运算符(%):…

    other 2023年6月27日
    00
  • Swift 字符串类型及常用方法详解总结

    下面我将为您详细讲解关于“Swift 字符串类型及常用方法详解”的攻略。 1. 字符串类型 Swift 中的字符串是一个由 Character 类型值组成序列,可以通过 String 类型来表示。在 Swift 中,字符串是值类型,并且使用 Unicode 编码表示。 定义一个字符串可以使用 String 关键字或者使用双引号 ” 包裹字符串字面量来定义。 …

    other 2023年6月20日
    00
  • ppt2019怎么使用ActiveX控件添加标签?

    当你在PPT2019中需要添加一些特定的功能或与外部程序进行交互时,你可能需要使用ActiveX控件。在PPT2019中,使用ActiveX控件来添加标签可以帮助你更好的管理幻灯片的内容,下面是详细的步骤。 步骤一:打开开发者选项 点击“文件”菜单,选择“选项”。 在“PowerPoint 选项”对话框中选择“自定义功能区”选项卡。 在右侧的“主选项卡”下拉…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部