背景知识:
二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树
eg:
本文主要介绍非递归方式
二叉树节点的定义:
class Node {
private int val;
private Node left;//左子树
private Node right;//右子树
public Node(int val) {
this.val = val;
}
public int getVal() {
return val;
}
public Node getLeft() {
return left;
}
public Node getRight() {
return right;
}
public void setLeft(Node left) {
this.left = left;
}
public void setRight(Node right) {
this.right = right;
}
}
递归方式实现的前中后序遍历
- 先序遍历
public static void preOrder(Node head) {
if(head == null) return;
System.out.print(head.getVal()+"-");
preOrder(head.getLeft());
preOrder(head.getRight());
}
- 中序遍历
public static void midOrder(Node head) {
if(head == null) return;
midOrder(head.getLeft());
System.out.print(head.getVal()+"-");
midOrder(head.getRight());
}
- 后序遍历
public static void lastOrder(Node head) {
if(head == null) return;
lastOrder(head.getLeft());
lastOrder(head.getRight());
System.out.print(head.getVal()+"-");
}
非递归方式实现前中后序遍历
先序遍历
思路:因为先序遍历的顺序是:头左右,利用一个栈,先将头节点入栈,然后栈不为空时就弹出(pop)节点,弹出就打印,然后先将右孩子节点入栈,再讲左孩子入栈(这样出站的顺序就是先左孩子再右孩子)
public static void preOrderNo(Node rootNode) {
if(rootNode == null) return;
Stack<Node> stack = new Stack<>();
stack.push(rootNode);
while(!stack.empty()) {
Node node = stack.pop();
System.out.print(node.getVal()+"-");
if(node.getRight() != null) {
stack.push(node.getRight());
}
if(node.getLeft() != null) {
stack.push(node.getLeft());
}
}
}
中序遍历
思路:从根结点开始依次将其左孩子入栈,直到左孩子为空,为空时就从栈中弹出(pop()方法)节点,弹出就打印,然后拿到弹出节点的右孩子(如果存在),将该右孩子右继续重复上一过程(判断左孩子是否存在,存在就入栈)
public static void midOrderNo(Node head) {
if(head == null) return;
Stack<Node> stack = new Stack<>();
while(!stack.isEmpty() || head != null) {
if(head != null) {
stack.push(head);
head = head.getLeft();
} else {
head = stack.pop();
System.out.print(head.getVal()+"-");
head = head.getRight();
}
}
}
后序遍历
思路:定义两个栈,先将头节点入栈,然后栈不为空时开始出栈,弹出一个节点就将该节点放入到另外一个栈中,然后将该节点的左右孩子入栈,入栈顺序按照:先左孩子(如果存在)入栈,再右孩子(如果存在)入栈,然后一直重复以上过程,知道栈为空,然后将另外一个栈依次出栈打印节点,就得到后序遍历
public static void lastOrderNo(Node head) {
if(head == null) return ;
Stack<Node> stack = new Stack<>();
Stack<Node> stack2 = new Stack<>();
stack.push(head);
while(!stack.empty()) {
Node cur = stack.pop();
stack2.push(cur);
if(cur.getLeft() != null) {
stack.push(cur.getLeft());
}
if(cur.getRight() != null) {
stack.push(cur.getRight());
}
}
while(!stack2.empty()) {
System.out.print(stack2.pop().getVal()+"-");
}
}
测试代码:
树结构:
public class MyTree {
public static void main(String[] args) {
Node node1 = new Node(1);
Node node2 = new Node(2);
node1.setLeft(node2);
Node node3 = new Node(3);
node1.setRight(node3);
Node node4 = new Node(4);
node2.setLeft(node4);
Node node5 = new Node(5);
node2.setRight(node5);
Node node6 = new Node(6);
node3.setLeft(node6);
Node node7 = new Node(7);
node6.setLeft(node7);
/* 1
2 3
4 5 6
7
*/
//先序遍历 头左右 预期:1 2 4 5 3 6 7
System.out.println("递归遍历的三种方式:");
System.out.println("先序遍历");
preOrder(node1);
System.out.println('\n'+"========================");
//中序遍历 左头右 预期:4 2 5 1 7 6 3
System.out.println("中序遍历");
midOrder(node1);
System.out.println('\n'+"========================");
//后序遍历 左右头 预期: 4 5 2 7 6 3 1
System.out.println("后序遍历");
lastOrder(node1);
System.out.println();
System.out.println("非递归遍历的三种方式:");
System.out.println("非递归先序遍历");
preOrderNo(node1);
System.out.println('\n'+"========================");
System.out.println("非递归中序遍历");
midOrderNo(node1);
System.out.println('\n'+"========================");
System.out.println("非递归后序遍历");
lastOrderNo(node1);
}
}
运行结果: