二叉树后序遍历(迭代方式+递归)
- 迭代方式
- 二叉树后序遍历时要注意,设置一个访问节点用来标识节点是否被访问,用一个动态数组来存储最后的结果,通过deque建立一个链表栈,设置一个外层大循环,
这个大循环是用来判断当前节点是否都是空或者栈中是否还有元素没加入到数组中,内层需要先往左边找,将左节点全部入栈,当访问到最后一个左节点的左孩子节点(这个左孩子节点实际是空),这个时候将栈中的最后一个左节点出栈进行
后续处理,首先判断这个节点的右节点是否被访问过了,或者右节点为空,如果这两个条件满足一个,那么就认为我们的该节点的左右节点均被访问过了,这时就将这个节点放到结果数组中,并赋值访问的标志,另设这个节点为空节点(相当于割去了);如果不是,那么就将右边的节点入栈,往右探索…
可以以下图为例自己试着走一遍,印象会更深刻。
3
/ \
9 4
/ \
5 7
//二叉树后序遍历,通过栈方式实现
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
TreeNode isVisited = null;
if(root == null){
return res;
}
Deque<TreeNode> stack = new LinkedList<>();
while(root != null || !stack.isEmpty()){//while(root != null && !stack.isEmpty()){
while(root != null){
stack.push(root);
root =root.left;
}
root=stack.pop();
if(root.right == null || root.right==isVisited){
res.add(root.val);
isVisited = root;
root = null;
}else{
stack.push(root);
root = root.right;
}
}
return res;
}
- 递归方式
递归方式相当于站在迭代的肩膀上进行的处理。比较好上手,两者区别在于迭代处理的时间较长,但是内存消耗较低;递归时间较短,但内存消耗较大。
public List<Integer> postorderTraversal(TreeNode root) {
ArrayList<Integer> al = new ArrayList<>();
return postertraver(root,al);
}
public ArrayList postertraver(TreeNode root, ArrayList al){
if(root == null){
return al;
}
postertraver(root.left,al);
postertraver(root.right,al);
al.add(root.val);
return al;
}
N叉树的迭代实现后续遍历
- N叉树实现后续遍历思路
1、将某节点入栈
2、某节点出栈,出栈的值放入链表的头部,然后其所有子节点入栈
3、循环1、2直到栈为空
public List<Integer> postorder(Node root) {
LinkedList<Integer> res = new LinkedList<>();
if(root == null){
return res;
}
Deque<Node> temp = new LinkedList<>();
//将一个点入栈,出栈时将节点记录,且将节点的所有子节点入栈,依次可得多叉树的后序遍历
temp.push(root);
while(!temp.isEmpty()){
Node node =temp.pop();
res.addFirst(node.val);
for(int i =0;i<node.children.size();i++){
temp.push(node.children.get(i));
}
}
return res;
}