二叉树的前序、中序、后序遍历,通过递归和非递归的方式实现【Java】
概述
二叉树的遍历" title="二叉树的遍历">二叉树的遍历,一个老生常谈的问题,大学的时候就天天学习,但是那时候大多是了解每中遍历的方式,但是并没有用代码实现,工作之后,使用代码实现一下。
三种遍历方式的区别
具体的介绍我这里就不说了,只总结性的说一下,所谓的前序,中序,后序,的前中后,其实就是根节点被访问的前中后,前序遍历就是根节点在最开始,中序遍历就是根节点在中间,后序遍历就是根节点在最后,当然这个根节点并不一定是二叉树的唯一根节点,而是每个节点只要有子节点,那这个节点其实都可以看作子节点的根节点。
下面就上代码
通过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
总结
不知道是年龄大了,还是智商本身太低,通过非递归的方式实现二叉树的遍历,想了好久都没有思路,只有前序遍历是自己独立实现的,后面的中序和后序都是参考网上的代码,不过也许这个也是一个熟能生巧的事。
以上是 二叉树的前序、中序、后序遍历,通过递归和非递归的方式实现【Java】 的全部内容, 来源链接: utcz.com/z/394532.html