题目
给定一个二叉树,返回它的 后序 遍历。
解题思路
本题我们不使用递归的方式,而是使用栈的方式来实现,这个技巧是一个模拟系统递归的过程,往后可以使用该技巧实现几乎所有的递归函数转非递归函数:
实例化两个栈,s1存储树节点,s2存储树节点的状态码,状态码共有3个值0,1,2;0代表该节点需要压入左节点,1代表该节点需要压入右节点,2代表左右子树都遍历完了,输出本节点。
代码
public List<Integer> postorderTraversal(TreeNode root) {
if(root == null){
return new ArrayList<Integer>();
}
//规定状态码为0时,需要压入左节点
//状态码为1时,需要压入右节点
//状态码为2时,表示无左右节点或者左右节点已遍历完,轮到该节点输出了,需要弹栈了
Stack<TreeNode> s1 = new Stack<TreeNode>();//栈1,用来存储具体的节点
Stack<Integer> s2 = new Stack<Integer>();//栈2,用来存储对应节点的状态码
List<Integer> list = new ArrayList<Integer>();//存储结果的数组
//初始化
s1.push(root);//根节点入栈
s2.push(0);//状态码0
while(!s1.empty()) {
switch (s2.peek()) {
case 0:
//如果左节点为空
if(s1.peek().left == null) {
s2.pop();
s2.push(1);//更新状态码
break;
}
//栈压入左节点
s1.push(s1.peek().left);
s2.pop();
s2.push(1);//更新状态码
s2.push(0);//为压入的左节点添置对应的状态码
break;
case 1:
if(s1.peek().right == null) {
s2.pop();
s2.push(2);
break;
}
//压入右子树
s1.push(s1.peek().right);
s2.pop();
s2.push(2);
s2.push(0);
break;
case 2:
list.add(s1.peek().val);
s1.pop();
s2.pop();
break;
}
}
return list;
}
总结
- 栈的应用场景非常广,就本题来看收获到的就是利用双栈来存储一个对象的地址和其对应的状态,不同的状态做不同的事,这是一种很实用的方法。