Java语言实现非递归实现树的前中后序遍历总结

 更新时间:2019年01月03日 14:35:04   作者:sdr_zd  
今天小编就为大家分享一篇关于Java语言实现非递归实现树的前中后序遍历总结,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

前言

三种遍历的递归写法都很好写,所以总结一下非递归写法。

先贴一张图复习一下三种遍历方式就进入正文啦~

【注:本文所有代码实现中树的结点定义如下:

public class Node {
  int val;
  Node left;
  Node right;
  Node parent;
  Node() {}
  Node(int val) {
    this.val = val;
  }
}

1.前序遍历

实现思路:

前序遍历的顺序是:根结点 -> 左孩子 -> 右孩子

借助一个栈结构先将根结点压入栈,然后循环每次取出栈顶元素,直到栈为空。如果当前结点有右孩子就先将右孩子压入栈中,如果当前结点有左孩子就将左孩子压入栈中,这里注意顺序,因为栈的结构是先进后出的,为了保证先遍历到左孩子就应该后压左孩子~

代码实现:

【代码使用直接输出的方式打印中序遍历结果,也可以放入一个list中存储~】

public void preOrder(Node head) {
    System.out.println("pre-order:");
    if(head != null) {
      Stack<Node> stack = new Stack<>();
      stack.push(head);
      while(!stack.isEmpty()) {
        head = stack.pop();
        System.out.print(head.val + " ");
        if (head.right != null)
          stack.push(head.right);
        if (head.left != null)
          stack.push(head.left);
      }
    }
  }

2.中序遍历

实现思路:

中序遍历的顺序:左孩子 -> 根结点 -> 右孩子

借助栈结构,将当前结点的左孩子依次入栈直到没有左孩子了就弹出栈顶元素并打印,如果弹出的结点有右孩子就将右孩子的左边界依次入栈,循环…

比如文章开始的那个图中,先将A,B,D依次入栈,此时栈顶元素是D,弹出并打印,D结点有右孩子,将D的右孩子的左边界依次入栈,压入结点G,结点G没有左孩子所以弹出并打印G,此时栈顶元素是B,循环…直到栈中为空且当前结点为空时遍历结束。

代码实现:

public static void inOrderTraverse(Node head) {
    System.out.println("in-order:");
    if(head != null) {
      Stack<Node> stack = new Stack<>();
      while(!stack.isEmpty() || head != null) {
        if(head != null) {
          // 当前节点不为空, 将自己压进栈并将自己的左孩子作为当前节点(压入左边界)
          stack.push(head);
          head = head.left;
        }else {
          // 当前节点为空(没有左孩子了), 将栈顶元素弹出作为当前节点, 并将当前节点的右孩子压进栈
          head = stack.pop();
          System.out.print(head.val + " ");
          head = head.right;
        }
      }
    }
  }

3.后序遍历

实现思路:

后序遍历的顺序:左孩子 -> 右孩子 -> 根结点

仔细想一下,打印每个结点需要访问根结点三次,先从根结点开始找到左孩子,返回再找到右孩子,再返回到根结点,需要访问根结点三次,直接按照当前顺序进行遍历不知如何下手,那么我们可以换一个角度去考虑。

栈结构是先进后出的,那我们不妨借助一个栈先存储 根结点 -> 右孩子 -> 左孩子 的结果,再将其依次弹出就是后序遍历的顺序了。

那实现 根结点 -> 右孩子 -> 左孩子 的方法就很简单了,回忆一下刚才说的前序遍历的方式,前序遍历是先要左孩子,就后压入左孩子,反之,将前序遍历的逻辑改写为:弹出每个栈顶结点作为当前结点并存储到一个辅助栈中,如果当前结点有左孩子就先压入左孩子,如果有右孩子就后压入右孩子,每次取栈顶弹出到辅助栈中。最后将得到的辅助栈中元素依次弹出得到的就是后序遍历的结果。

代码实现:

public static void posOrderTraverse(Node head) {
    System.out.println("pos-order");
    if(head != null) {
      Stack<Node> stack1 = new Stack<>();
      Stack<Node> stack2 = new Stack<>();   // 辅助栈,存储 根 -> 右 -> 左 的结果
      stack1.push(head);
      while(!stack1.isEmpty()) {
        head = stack1.pop();
        stack2.push(head);
        // 有左孩子就先压入左孩子
        if(head.left != null)
          stack1.push(head.left);
        // 有右孩子就后压入右孩子
        if(head.right != null)
          stack1.push(head.right);
      }
      // 逆序打印 根 -> 右 -> 左 的结果,就是后序遍历的结果
      while(!stack2.isEmpty())
        System.out.print(stack2.pop().val + " ");
    }
  }

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。如果你想了解更多相关内容请查看下面相关链接

相关文章

  • spring cloud 之 Feign 使用HTTP请求远程服务的实现方法

    spring cloud 之 Feign 使用HTTP请求远程服务的实现方法

    下面小编就为大家带来一篇spring cloud 之 Feign 使用HTTP请求远程服务的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • JAVA爬虫实现自动登录淘宝

    JAVA爬虫实现自动登录淘宝

    给大家分享一个关于JAVA爬虫的相关知识点,通过代码实现自动登录淘宝网,有兴趣的朋友测试下。
    2018-04-04
  • Spring boot 打jar包分离lib的正确配置方式

    Spring boot 打jar包分离lib的正确配置方式

    spring boot打jar包分离lib后,配置文件的方式,在网上可以搜到很多答案,但是都不够完善,今天小编给大家带来了Spring boot 打jar包分离lib的正确配置方式,感兴趣的朋友一起看看吧
    2018-02-02
  • jmeter正则表达式提取器的用法与正则详解

    jmeter正则表达式提取器的用法与正则详解

    在使用Jmeter过程中,会经常使用到正则表达式提取器提取器,下面这篇文章主要给大家介绍了关于jmeter正则表达式提取器的用法与正则的相关资料,需要的朋友可以参考下
    2022-07-07
  • java并发编程包JUC线程同步CyclicBarrier语法示例

    java并发编程包JUC线程同步CyclicBarrier语法示例

    这篇文章主要为大家介绍了java并发编程工具包JUC线程同步CyclicBarrier语法使用示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • 这一次搞懂Spring的Bean实例化原理操作

    这一次搞懂Spring的Bean实例化原理操作

    这篇文章主要介绍了这一次搞懂Spring的Bean实例化原理操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • IDEA的基本使用(让你的IDEA有飞一般的感觉)

    IDEA的基本使用(让你的IDEA有飞一般的感觉)

    这篇文章主要介绍了IDEA的基本使用(让你的IDEA有飞一般的感觉),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • 两行Javascript代码生成UUID的方法

    两行Javascript代码生成UUID的方法

    这篇文章主要介绍了两行Javascript代码生成UUID的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • SpringBoot起步依赖和自动配置基本介绍

    SpringBoot起步依赖和自动配置基本介绍

    这篇文章主要介绍了SpringBoot起步依赖和自动配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • java多线程下载实例详解

    java多线程下载实例详解

    这篇文章主要介绍了java多线程下载,结合实例形式详细分析了Java多线程文件传输的原理与多线程下载的相关实现技巧,需要的朋友可以参考下
    2015-12-12

最新评论