对于二叉树的后序遍历,我们前面介绍了一种使用递归的方式,这种比较简单,还有两种使用栈的方式,但是这里都是选择了使用两个栈。
那么能不能使用一个栈来完成呢?显然是可以呢。那么具体怎么操作呢?这里也有很多思路,我们这里介绍两种比较常规的思路。
第一种是用一个临时变量来保存访问过的节点,它的主要目的是判断一个节点的左右子树是否均被访问完成。
如果一个节点的左右子树均被访问了,那么我们就可以访问这个节点,否则就按照右子树、左子树的方式进行压栈,以备后续处理。
我们来看一下具体的实现吧:
package com.mengzhidu.teach.algorithm.tree.demo.traversal;
import com.mengzhidu.teach.algorithm.tree.demo.TreeNode;
import com.mengzhidu.teach.algorithm.tree.demo.TreeNodeHelper;
import java.util.Stack;
/**
* 根据单栈法来实现二叉树的后序遍历
* 它这里用一个变量last来保存当前最后访问的节点,它必须在访问后设置
* 如何来判断一个节点node的左右子树都被访问呢?
* 使用: (node.right == null && node.left == last) || node.right == last
*
* 它的思路就是:
* 如果一个节点的左右子树均被访问过或者是叶子节点,那么就访问它
* 否则把右子树和左子树依次压入到栈中
*/
public class PostOrderDemo4 {
public static void main(String[] args) {
TreeNode current = TreeNodeHelper.getTreeNode();
TreeNode last = null;
Stack<TreeNode> stack = new Stack<>();
stack.push(current);
while (!stack.isEmpty()) {
current = stack.peek();
boolean emptyNode = current.getRight() == null && current.getLeft() == null;
boolean visited = (current.getRight() == null && current.getLeft() == last) || current.getRight() == last;
if (emptyNode || visited) {
stack.pop();
System.out.println(current.getValue());
last = current;
} else {
if (current.getRight() != null) {
stack.push(current.getRight());
}
if (current.getLeft() != null) {
stack.push(current.getLeft());
}
}
}
}
}
第二种就是采用压栈两次的方式,对于某个特定的节点,当它第一次出栈的时候,它会把右子树和左子树给压进去,当它第二次出栈的时候,它会把自己打印出来。
其实它的思想和第一种方法没有本质的区别,我们来看一下代码实现吧:
package com.mengzhidu.teach.algorithm.tree.demo.traversal;
import com.mengzhidu.teach.algorithm.tree.demo.TreeNode;
import com.mengzhidu.teach.algorithm.tree.demo.TreeNodeHelper;
import java.util.Stack;
/**
* 使用单栈方式的后序遍历
* 这里使用压栈两次的方法,第一次出栈是把孩子压进去,第二次出栈是访问自己
*/
public class PostOrderDemo5 {
public static void main(String[] args) {
TreeNode current = TreeNodeHelper.getTreeNode();
Stack<TreeNode> stack = new Stack<>();
stack.push(current);
stack.push(current);
while (!stack.isEmpty()) {
current = stack.pop();
if (!stack.isEmpty() && current == stack.peek()) {
if (current.getRight() != null) {
stack.push(current.getRight());
stack.push(current.getRight());
}
if (current.getLeft() != null) {
stack.push(current.getLeft());
stack.push(current.getLeft());
}
} else {
System.out.println(current.getValue());
}
}
}
}
对于树的后序遍历,我们就介绍到这里啦。