zoukankan      html  css  js  c++  java
  • 二叉树的前序、中序、后序遍历,通过递归和非递归的方式实现【Java】

    概述

      二叉树的遍历,一个老生常谈的问题,大学的时候就天天学习,但是那时候大多是了解每中遍历的方式,但是并没有用代码实现,工作之后,使用代码实现一下。

    三种遍历方式的区别

      具体的介绍我这里就不说了,只总结性的说一下,所谓的前序,中序,后序,的前中后,其实就是根节点被访问的前中后,前序遍历就是根节点在最开始,中序遍历就是根节点在中间,后序遍历就是根节点在最后,当然这个根节点并不一定是二叉树的唯一根节点,而是每个节点只要有子节点,那这个节点其实都可以看作子节点的根节点。

    下面就上代码

    通过java自己实现二叉树

    先定义节点

     1 package com.example.demo.tree;
     2 
     3 /**
     4  * @author steve
     5  * @date 2020/4/18 3:16 下午
     6  */
     7 public class Node<E> {
     8     public Node<E> left;
     9     public Node<E> right;
    10     public Node<E> parent;
    11     public E element;
    12     public Node(E element){
    13         this.element = element;
    14     }
    15 }
    View Code

    定义二叉树

     1 package com.example.demo.tree;
     2 
     3 import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
     4 import org.omg.PortableInterceptor.INACTIVE;
     5 
     6 import java.util.Comparator;
     7 
     8 /**
     9  * @author steve
    10  * @date 2020/4/16 10:03 上午
    11  */
    12 public class BinaryTree<E> {
    13 
    14     private int size;
    15     public Node<E> root;
    16     private Comparator<E> comparator;
    17 
    18     public BinaryTree(Comparator<E> comparator){
    19         this.comparator = comparator;
    20     }
    21 
    22     public BinaryTree(){
    23         this(null);
    24     }
    25 
    26     public void add(E element){
    27         if (root == null){
    28             Node node = new Node(element);
    29             root = node;
    30         }else {
    31             Node<E> parent = root;
    32             Node<E> node = root;
    33             int com = 0;
    34             while (node != null){
    35                 parent = node;
    36                 if (comparator == null){
    37                     com = ((Comparable)node.element).compareTo(element);
    38                 }else {
    39                     System.out.println("-------------");
    40                     com = comparator.compare(node.element,element);
    41                 }
    42                 if (com > 0){
    43                     node = node.left;
    44                 }else if (com < 0){
    45                     node = node.right;
    46                 }else {
    47                     node.element = element;
    48                     return;
    49                 }
    50             }
    51             Node<E> newNode = new Node(element);
    52             if (com > 0){
    53                 parent.left = newNode;
    54                 newNode.parent = parent.left;
    55             }else{
    56                 parent.right = newNode;
    57                 newNode.parent = parent.right;
    58             }
    59         }
    60         size ++;
    61     }
    62     public boolean isEmpty(){
    63         return size == 0;
    64     }
    65     public int size(){
    66         return size;
    67     }
    68 
    69     public String toString() {
    70         String d = root == null ? null : root.element + "";
    71         if (root == null){
    72             return "root:"+d;
    73         }else {
    74             String b = root.left == null ? null : root.left.element + "";
    75             String c = root.right == null ? null : root.right.element + "";
    76             return "root:"+d + ", left:" + b + ", right:"+ c;
    77         }
    78 
    79     }
    80 
    81 
    82     public static void main(String[] args) {
    83         //这种方式就是匿名内部类,通过给一个类传一个接口作为参数,然后这个通过一个匿名内部类是实现这个接口来传入实现。
    84         BinaryTree<Integer> binaryTree = new BinaryTree<>(new Comparator<Integer>() {
    85             @Override
    86             public int compare(Integer o1, Integer o2) {
    87                 return o1 - o2;
    88             }
    89         });
    90 
    91         BinaryTree<Integer> binaryTree1 = new BinaryTree<>();
    92         binaryTree1.add(1);
    93         binaryTree1.add(2);
    94         binaryTree1.add(0);
    95         System.out.println(binaryTree1.size());
    96         System.out.println(binaryTree.toString());
    97     }
    98 }
    View Code

    遍历二叉树

      1 package com.example.demo.tree;
      2 
      3 import sun.tools.native2ascii.resources.MsgNative2ascii;
      4 
      5 import java.util.*;
      6 
      7 /**
      8  * @author steve
      9  * @date 2020/4/18 2:58 下午
     10  * 遍历二叉树,分别使用递归和迭代进行前序中序后序遍历一颗二叉树
     11  */
     12 public class TraversBinaryTree {
     13 
     14     /**
     15      * 前序遍历
     16      * 从根节点开始,先遍历左子树,后遍历右子树
     17      */
     18     public static void preOrderTraveral(Node<Integer> node){
     19         if (node == null) return;
     20         System.out.println(node.element);
     21         preOrderTraveral(node.left);
     22         preOrderTraveral(node.right);
     23     }
     24 
     25     /**
     26      * 前序遍历,不使用递归实现
     27      * 解释:前序遍历是最简单的,因为这个是从头开始的,不用像中序遍历和后序遍历一样,都是从最低级的左孩子开始,所以这个,只需要一直入栈右孩子,
     28      * 左孩子,就可以了,其实这个过程一遍下来之后,所有的左孩子都出栈了,剩下的就是右孩子,那再慢慢出栈就可以了。
     29      * @param node
     30      */
     31     public static void preOrderTraveralUseStack(Node<Integer> node){
     32         Stack<Node<Integer>> stack = new Stack<>();
     33         stack.push(node);
     34         while (!stack.isEmpty()){
     35             Node<Integer> node1 = stack.pop();
     36             System.out.println(node1.element);
     37             if (node1.right != null){
     38                 stack.push(node1.right);
     39             }
     40             if (node1.left != null){
     41                 stack.push(node1.left);
     42             }
     43         }
     44     }
     45 
     46     /**
     47      * 中序遍历二叉树
     48      * 根节点在中间,从最左边的节点开始,先左后中,后右,遍历
     49      */
     50     public static void inOrderTraveral(Node<Integer> node){
     51         if (node == null) return;
     52         inOrderTraveral(node.left);
     53         System.out.println(node.element);
     54         inOrderTraveral(node.right);
     55 
     56     }
     57 
     58     /**
     59      * 中序遍历,不使用递归实现
     60      * 解释:这个其实比后序遍历简单,因为,这个先压入中,之后压入左,在出栈的时候,可以直接按照这个顺序反着出栈,然后在这个过程中
     61      * 只需要判断有没有右孩子,而不用担心右孩子重复入栈的问题,但是后序遍历就需要考虑这个问题
     62      * @param node
     63      */
     64     public static void inOrderTraveralUseStack(Node<Integer> node){
     65         if (node == null) return;
     66         Stack<Node<Integer>> stack = new Stack<>();
     67         stack.push(node);
     68         while (!stack.isEmpty()){
     69             if (node != null && node.left != null){
     70                 stack.push(node.left);
     71                 node = node.left;
     72             }else {
     73                 //已经弹出来的节点,其左孩子不能再入栈
     74                 node = stack.pop();
     75                 System.out.println(node.element);
     76                 if (node.right != null){
     77                     stack.push(node.right);
     78                     node = node.right;
     79                 }else {
     80                     node = null;
     81                 }
     82             }
     83         }
     84 
     85     }
     86 
     87     /**
     88      * 后序遍历
     89      * 根节点最后遍历,先左后右,之后中间的
     90      */
     91     public static void postOrderTraveral(Node<Integer> node){
     92         if (node == null) return;;
     93 
     94         postOrderTraveral(node.left);
     95         postOrderTraveral(node.right);
     96         System.out.println(node.element);
     97     }
     98 
     99     /**
    100      * 后序遍历,不使用递归,使用栈的方式实现
    101      * 1.先把左孩子压入栈,如果没有左孩子了,弹出左孩子
    102      * 2.然后把右孩子压入栈,如果没有了,就弹出
    103      * 注意:
    104      * 1.这里要注意两个点,第一个点就是如果一个节点的左孩子和右孩子都已经判断完了,那么就把这个节点置为null
    105      * 2.如果一个节点的右孩子已经处理过了,就不要重复入栈
    106      * 总结:
    107      * 1.不能重复入栈,无论是左孩子还是右孩子
    108      * @param node
    109      */
    110     public static void postOrderTraveralUseStack(Node<Integer> node){
    111         if (node == null) return;
    112         Stack<Node<Integer>> stack = new Stack<>();
    113         stack.add(node);
    114         Node<Integer> node2 = null;
    115         while (!stack.isEmpty()){
    116             if (node != null && node.left != null){
    117                 stack.push(node.left);
    118                 node = node.left;
    119             }else {
    120                 node = stack.peek();
    121                 if (node.right != null && node.right != node2){
    122                     stack.push(node.right);
    123                     //这里为了防止右孩子重复入栈
    124                     node2 = node.right;
    125                     node = node.right;
    126                 }else {
    127                     stack.pop();
    128                     System.out.println(node.element);
    129                     //这里为了防止右孩子重复入栈
    130                     node2 = node;
    131                     //这里为了防止左孩子重复入栈
    132                     node = null;
    133                 }
    134             }
    135         }
    136     }
    137 
    138     /**
    139      * 层序遍历二叉树
    140      * 使用队列实现,而不是栈
    141      */
    142     public static void levelOrderTraveral(Node<Integer> node){
    143         Queue<Node<Integer>> queue = new LinkedList<>();
    144         queue.add(node);
    145         while(!queue.isEmpty()){
    146             Node<Integer> node1 = queue.peek();
    147             queue.poll();
    148             System.out.println(node1.element);
    149             if (node1.left != null){
    150                 queue.add(node1.left);
    151             }
    152             if (node1.right != null){
    153                 queue.add(node1.right);
    154             }
    155         }
    156     }
    157 
    158     public static void main(String[] args) {
    159         BinaryTree<Integer> binaryTree = new BinaryTree<>();
    160         binaryTree.add(7);
    161         binaryTree.add(4);
    162         binaryTree.add(10);
    163         binaryTree.add(9);
    164         binaryTree.add(11);
    165         binaryTree.add(5);
    166         binaryTree.add(3);
    167         System.out.println("------------preorder traveral use recursion---------");
    168         TraversBinaryTree.preOrderTraveral(binaryTree.root);
    169         System.out.println("------------preorder traveral use stack");
    170         TraversBinaryTree.preOrderTraveralUseStack(binaryTree.root);
    171         System.out.println("-------------inorder traveral use recursion-------------------");
    172         TraversBinaryTree.inOrderTraveral(binaryTree.root);
    173         System.out.println("-------------inorder traveral use stack----------------");
    174         TraversBinaryTree.inOrderTraveralUseStack(binaryTree.root);
    175         System.out.println("--------------postorder traveral use recursion------------------");
    176         TraversBinaryTree.postOrderTraveral(binaryTree.root);
    177         System.out.println("--------------postorder traveral use stack-----------");
    178         TraversBinaryTree.postOrderTraveralUseStack(binaryTree.root);
    179         System.out.println("--------------------------------");
    180         TraversBinaryTree.levelOrderTraveral(binaryTree.root);
    181     }
    182 
    183 }
    View Code

    总结

      不知道是年龄大了,还是智商本身太低,通过非递归的方式实现二叉树的遍历,想了好久都没有思路,只有前序遍历是自己独立实现的,后面的中序和后序都是参考网上的代码,不过也许这个也是一个熟能生巧的事。

  • 相关阅读:
    Table to List<object> C#
    Edge Beta 进入无痕模式 快捷方式
    C# 按行读取文件 从某行开始取
    Navicat连接oracle,出现Only compatible with oci version 8.1
    未能找到 System.Web.Helpers
    js json 排序
    使用 NPM 安装Vue并创建项目
    css3动效
    回忆向——诺宝RC机器人仿真
    javascript问题
  • 原文地址:https://www.cnblogs.com/gunduzi/p/12739556.html
Copyright © 2011-2022 走看看