二叉树迭代遍历

98 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第21天,点击查看活动详情

二叉树迭代遍历

推荐阅读:二叉树的迭代遍历

前序遍历

前序遍历是先处理中间节点在处理左右节点。(中左右)

  • 写入根节点,不断迭代左节点直到叶子节点
  • 从左叶子节点往上,判断是否有右子节点
    • 有则入栈,再次迭代,进行同样的操作
    • 没有,则左节点层数向上。
  • 直到切片为空或者没有右子节点,遍历完成
func preorderTraversal(root *TreeNode) []int {
    stack:=[]*TreeNode{}
    ans:=[]int{}
    node:=root
    for node!=nil||len(stack)>0{//栈不为空 
        //判断当前节点是否为空
        for node!=nil{
            ans=append(ans,node.Val)
            stack=append(stack,node)
            node=node.Left
        }
        //拿到当前层的左节点
        node=stack[len(stack)-1]
        stack=stack[:len(stack)-1]//弹出当前节点,层数向上,下次取就是根节点
        node=node.Right//迭代右节点
    }
    return ans

}

感觉思想有点像递归!!!团子的感觉!!🤣😅

中序遍历

中序遍历是先处理左节点,然后处理中节点和右节点(左中右)

其实思想与前序差不多,只是需要先遍历到左叶子节点,然后逐渐往上遍历中节点,之后处理右节点。具体的可以通过代码理解!

func inorderTraversal(root *TreeNode) []int {
    stack:=[]*TreeNode{}
    node:=root
    ans:=[]int{}
    for node!=nil||len(stack)>0{
        for node!=nil{//遍历当前节点的左节点到左叶子节点
            stack=append(stack,node)
            node=node.Left
        }
        node=stack[len(stack)-1]//拿到当前层的左节点
        stack=stack[:len(stack)-1]//弹出当前节点,层数向上,下一次取就是根节点
        ans=append(ans,node.Val)//获取当前节点值
        node=node.Right//迭代右节点
    }
    return ans
}

你会发现前序和中序的区别就是获取当前值的位置不同

后序遍历

后序遍历是先处理左节点,然后就处理右节点,之后处理中节点(左右中)

前序遍历是中左右

后序遍历是左右中

有没有发现一个特点!!!😋😋😋快想想!

你把前序遍历的顺序改成中右左,之后再首尾交换,是不是就是左右中了,这不就是后序遍历吗?!!🎉🎉🎉

  • 改变前序遍历的顺序为中右左
  • 遍历后的值首尾交换
func postorderTraversal(root *TreeNode) []int {
    stack:=[]*TreeNode{}
    ans:=[]int{}
    node:=root
    for node!=nil||len(stack)>0{
        for node!=nil{//遍历中节点
            ans=append(ans,node.Val)
            stack=append(stack,node)
            node=node.Right//遍历右节点
        }
        node=stack[len(stack)-1]//拿到当前层的右节点
        stack=stack[:len(stack)-1]//层数向上,下一次取就是根节点
        node=node.Left//迭代左节点
    }
    Reverse(ans)
    return ans
}
func Reverse(num []int){//完成首尾交换工作
    for i:=0;i<len(num)/2;i++{
        num[i],num[len(num)-i-1]=num[len(num)-i-1],num[i]
    }
}

有没有一种很神奇的感觉!!!

上面一种方法比较取巧了!

下面是比较正式的后序遍历

func postorderTraversal(root *TreeNode) (res []int) {
    stk := []*TreeNode{}
    var prev *TreeNode
    //左右中
    for root != nil || len(stk) > 0 {
        for root != nil {
            stk = append(stk, root)
            root = root.Left
            //遍历到左叶子结点
        }
        root = stk[len(stk)-1]
        stk = stk[:len(stk)-1]
        // 需要先写入右孩子节点 判断右孩子是否为空 为空就填值 不为空就放回栈 遍历右孩子的子树
        //防止再次遍历一次右节点,需要记录之前遍历的节点(右节点)
        if root.Right == nil || root.Right == prev {
            res = append(res, root.Val)
            prev = root
            root = nil
        } else {
            stk = append(stk, root)
            root = root.Right
        }
    }
    return
}

前中后序的遍历用一种代码全部完成了!!!!三种遍历的代码变化都不是很大!!!!理解后,你就可以秒杀二叉树遍历了!!快夸夸团子!!😘😘😘

练手题目:

参考资料:

programmercarl.com/%E4%BA%8C%E…

blog.csdn.net/weixin_4446…