二叉树非递归遍历最简洁的方式

文章目录


最近重新复习二叉树的非递归遍历方式,发现前中后序遍历实现的思想都不一致,导致要理解很多种递归的思路,有点痛苦。

对于递归遍历,思路非常明确,理解和记忆也都没有什么困难。
如下根据不同的访问顺序就可以实现先中后序的访问。

func traversal(root *TreeNode, r *[]int) {
    if root==nil{
        return 
    }
    //*r = append(*r, root.Val);  //先序遍历
    traversal(root.Left, r)
    //*r = append(*r, root.Val);  //中序遍历
    traversal(root.Right, r)
    //*r = append(*r, root.Val);  //后序遍历
}

下面把非递归的方式也归结成统一的思想:
前中序的非递归实现一般用回溯法,每次左子树遍历完之后才回溯。使用一个辅助栈,从根节点开始,如果节点不为空,就一直入栈,并更新节点为当前节点的左节点。节点为空时说明左子树处理完毕,此时将左子树出栈,处理右子树。因此:
节点在入栈的时候访问,就是前序遍历。
节点在出栈的时候访问,就是中序遍历。

type stack []*TreeNode
func pop(s *stack) *TreeNode{
    node  := *stack[len(stack)-1]    
    *stack = *stack[:len(stack)-1]  
    return node
}
func push(s *stack, *TreeNode) {
    *stack = append(*stack, node)
}

func traversal(root *TreeNode) []int {
    r := make([]int, 0, 0)
    s := make(stack, 0, 0)

    node := root
    for len(s)!= 0 || node!=nil {
        if node != nil {         
            //r = append(r, node.Val) //在入栈的时候访问,就是前序遍历
            push(&s, node)
            node = node.Left
        } else {
            node = pop(&s)
           //r = append(r, node.Val) //在出栈的时候访问,就是中序遍历
            node = node.Right
        }
    }
    return r
}

接下来看了很多后序遍历的实现都不好理解,其实后序遍历就是 根->右->左 的逆序遍历,我们换个思路,先得到 根->右->左 的遍历结果,再反序就可以了,根->右->左就是前序遍历根->左->右的变种,上述前序遍历的代码交换以下 Left 和 Right 的入栈顺序即可,因此后序遍历的代码如下

type stack []*TreeNode
func pop(s *stack) *TreeNode{
    node  := *stack[len(stack)-1]    
    *stack = *stack[:len(stack)-1]  
    return node
}
func push(s *stack, *TreeNode) {
    *stack = append(*stack, node)
}

func traversal(root *TreeNode) []int {
    r := make([]int, 0, 0)
    s := make(stack, 0, 0)

    node := root
    for len(s)!= 0 || node!=nil {
        if node != nil {         
            r = append(r, node.Val) 
            push(&s, node)
            node = node.Right
        } else {
            node = pop(&s)
            node = node.Left
        }
    }
    //上面已经得到了根->右->左的顺序,反转一遍就是后序遍历的结果了
    r2 := make([]int, 0, len(r))
    for i:=len(r)-1; i>=0 ;i--{
        r2 = append(r2, r[i])
    }
    return r2
}

这样看来,所有的遍历都可以用一种回溯的方法解决了。

你可能感兴趣的:(算法)