二叉树的递归遍历代码是很直观的,但是非递归遍历时不是那么直观,特别是中序遍历和后续遍历。
中序遍历非递归实现
中序遍历需要先访问左节点,然后访问根节点,最后访问右节点。
我们参考递归代码找寻思路:
1. if (root == null) {return;}
2. midOrder(root.leftChild);
3. System.out.println(root.data);
4. midOrder(root.rightChild);
递归先找到最左面的节点,这里我们可以while和栈模拟实现
//对应递归第二句 midOrder(root.leftChild);
while (root != null) {
stack.push(root);
root = root.leftChild;
}
root为空意味着我们要出栈,因此可以下面代码模拟递归函数返回:
//对应递归算法第一句 if (root == null) {return;}
//递归算法里走到上面这的时候,代表root.leftChild == null,return返回上一次调用
root = stack.pop();
//对应递归算法第三句
System.out.println(root.data);
之后,递归算法将右节点传入继续执行递归,所以我们需要root = root.rightChild
,然后将root重新执行上面算法,因此我们需要将上面算法再用一层while套住。
最终的非递归实现:
private void midOrder2(Node<T> root) {
if (root == null) {
return;
}
Stack<Node<T>> stack = new Stack<>();
while (root != null || !stack.empty()) {
//模拟递归入栈
while (root != null) {
stack.push(root);
root = root.leftChild;
}
root = stack.pop();
System.out.println(root.data);
root = root.rightChild;
}
}
/**
* Created by 默默 on 2018/3/1.
*/
import java.util.Stack;
public class BinaryTree<T> {
public static class Node<T> {
T data;
Node<T> leftChild;
Node<T> rightChild;
public Node(T data, Node<T> leftChild, Node<T> rightChild) {
super();
this.data = data;
this.leftChild = leftChild;
this.rightChild = rightChild;
}
}
public Node<T> root;
public BinaryTree(Node<T> root) {
super();
this.root = root;
}
public void preOrder() {
preOrder(root);
}
/**
* 递归实现
*
* @param root
*/
private void preOrder(Node<T> root) {
if (root == null) {
return;
}
System.out.println(root.data);
preOrder(root.leftChild);
preOrder(root.rightChild);
}
public void preOrder2() {
preOrder2(root);
}
/**
* 栈实现
*/
private void preOrder2(Node<T> root) {
if (root == null) {
return;
}
Stack<Node<T>> stack = new Stack<>();
stack.push(root);
while (!stack.empty()) {
Node<T> node = stack.pop();
System.out.println(node.data);
if (node.rightChild != null) {
stack.push(node.rightChild);
}
if (node.leftChild != null) {
stack.push(node.leftChild);
}
}
}
public void midOrder() {
midOrder(root);
}
private void midOrder(Node<T> root) {
if (root == null) {
return;
}
midOrder(root.leftChild);
System.out.println(root.data);
midOrder(root.rightChild);
}
public void midOrder2() {
midOrder2(root);
}
/**
* 栈实现中序遍历
*/
private void midOrder2(Node<T> root) {
if (root == null) {
return;
}
Stack<Node<T>> stack = new Stack<>();
while (root != null || !stack.empty()) {
//模拟递归入栈
while (root != null) {
stack.push(root);
root = root.leftChild;
}
root = stack.pop();
System.out.println(root.data);
root = root.rightChild;
}
}
public void postOrder2() {
postOrder2(root);
}
private void postOrder2(Node<T> root) {
if (root == null) {
return;
}
Stack<Node<T>> stack = new Stack<>();
Node<T> lastVisitedNode = null;
while (root != null || !stack.empty()) {
//一直到左子树最下边
while (root != null) {
stack.push(root);
root = root.leftChild;
}
Node<T> node = stack.pop();
/**
* 右子树不为空并且还没有被访问,当前节点重新入栈,访问右节点
*/
if (node.rightChild != null && node.rightChild != lastVisitedNode) {
stack.push(node);
root = node.rightChild;
} else {
System.out.println(node.data);
root = null;
记录上一次访问的节点
lastVisitedNode = node;
}
}
}
public static void main(String[] args) {
/**
* A
* / \
* B C
* / / \
* D E F
* / \ \
* G H I
*/
Node<String> gNode = new Node<String>("G", null, null);
Node<String> hNode = new Node<String>("H", null, null);
Node<String> iNode = new Node<String>("I", null, null);
Node<String> fNode = new Node<String>("F", null, null);
Node<String> dNode = new Node<String>("D", gNode, hNode);
Node<String> eNode = new Node<String>("E", null, iNode);
Node<String> bNode = new Node<String>("B", dNode, null);
Node<String> cNode = new Node<String>("C", eNode, fNode);
Node<String> root = new Node<String>("A", bNode, cNode);
BinaryTree<String> tree = new BinaryTree<String>(root);
//ABDGHCEIF
//tree.preOrder2();
//GDHBAEICF
//tree.midOrder2();
//GHDBIEFCA
//tree.postOrder2();
}
}