Fork me on GitHub

二叉树的前序、中序、后序遍历,通过递归和非递归的方式实现【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

总结

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

posted @ 2020-04-20 18:21  猿起缘灭  阅读(473)  评论(0编辑  收藏  举报