LeetCode590. N叉树的后序遍历(Java实现)

题目描述: 给定N叉树,输出其后序遍历序列。
给定的N叉树节点类为:

class Node {
    public int val;
    public List<Node> children;

    public Node() {}

    public Node(int _val,List<Node> _children) {
        val = _val;
        children = _children;
    }
}

如图N叉树:
LeetCode590. N叉树的后序遍历(Java实现)_第1张图片
其后序遍历序列为:[4,5,1,2,6,7,3,0]

解题思路: 通常树的深度遍历问题有两种解法,一个是使用递归方法,另一个是借助栈来完成。下面分别介绍该题目使用这两种方法的具体解法。

  1. 递归法:使用递归算法,通常是将一个问题可以分解为子问题,而子问题的解决方法和原问题一致。
    就该题来说,求解后序遍历,从根节点开始,需要从左到右求解其每个子节点的后序遍历序列之后再加上根节点自身,对于其子节点来说,一样是从左至右求解其子节点的后序遍历序列,之后再添加上自己。
    递归的终止条件: 当当前节点不存在子节点时,就可以返回了。

按照上面的思路,递归法的代码如下:

public static void postOrder(Node root, List<Integer> list){
    if(root == null)
        return;
    List<Node> children = root.children;
    if(children == null){
        list.add(root.val);
        return;
    }
    for(Node node : children){
        postOrder(node, list);
    }
    list.add(root.val);
}
  1. 借用栈的方法:
    Q:为什么要使用栈?
    A:树的深度遍历是会先到最低层,即树的叶子节点,之后才会开始向上一层一层的返回,而我们一开始是从根节点开始遍历的,这种访问过程,和栈的后进先出性质十分吻合,因此,借用栈来完成遍历过程。

    整个算法图解过程:
    给定N叉树,如图:
    LeetCode590. N叉树的后序遍历(Java实现)_第2张图片
    用一个list保存遍历序列
    一开始将根节点0入栈,此时栈顶节点为0,如图①,判断栈顶节点的子节点是否为空,若不是,则将子节点倒序压入栈中如图②,否则,栈顶对象出栈
    LeetCode590. N叉树的后序遍历(Java实现)_第3张图片
    此时继续对栈顶节点进行判断,继续倒序压入节点,如图③
    LeetCode590. N叉树的后序遍历(Java实现)_第4张图片
    此时,栈顶元素4没有子节点,因此需要出栈,5也没有,同样出栈,栈又回到②的结构,list:[4,5]。1的子节点已经全部入栈后又出栈,此时需要将1出栈。所以将1弹出栈,2也没有子节点因此出栈,如图④,list:[4,5,1,2]
    LeetCode590. N叉树的后序遍历(Java实现)_第5张图片
    3有子节点,因此需要将其倒序压入栈,如图⑤
    LeetCode590. N叉树的后序遍历(Java实现)_第6张图片
    6,7均没有子节点,继续出栈,到此,3,的子节点也全部入栈后出栈,0也一样,因此,依次出栈。栈空,list:[4,5,1,2,6,7,3,0]

从上述解题过程,可以看出:
入栈情况只有一种:栈顶节点有子节点时,需要将子节点倒序依次压入栈中。
出栈的情况有两种:
1) 当当前栈顶节点没有子节点时,需要出栈
2)当前栈顶节点的全部子节点已经进栈又出栈后,当前栈顶节点需要出栈。(这种情况我的判断方法是,判断当前节点和刚弹出栈的节点之间是否是父子关系,如果是,说明其子节点已经全部弹出,该节点需要出栈)

具体代码如下:

public static void postOrder2(Node root, List<Integer> list){
    if(root == null)
        return;
    Stack<Node> helper = new Stack<>();
    helper.push(root);
    Node curNode = null;
    Node preNode = null;
    while(!helper.isEmpty()){
        curNode = helper.peek();
        List<Node> children = curNode.children;
        if(children.size()==0 || (preNode != null && children.get(children.size()-1) == preNode)){
            list.add(curNode.val);
            preNode = curNode;
            helper.pop();
        }else {
            for (int i = children.size() - 1; i >= 0; i--) {
                helper.push(children.get(i));
            }
        }

    }
}

你可能感兴趣的:(数据结构与算法,后序遍历,N叉树)