[Go版]算法通关村——迭代实现二叉树的前中后序遍历

目录

  • 迭代实现遍历二叉树
  • 迭代实现二叉树的前序遍历
    • 思路分析:栈
    • Go代码
  • 迭代实现二叉树的后序遍历
    • 思路分析:栈+反转数组
    • Go代码
  • 迭代实现二叉树的中序遍历
    • 思路分析:栈+指针
    • Go代码

迭代实现遍历二叉树

用递归做二叉树的遍历是非常简单,只需要几行代码就可以搞定。
那我们知道递归的底层使用的还是栈,所以只要使用递归方式能解决的问题,都可以使用迭代(非递归)来解决。我们可以使用栈来模拟递归的过程。

迭代实现二叉树的前序遍历

题目链接:LeetCode-144. 二叉树的前序遍历

思路分析:栈

前序遍历:中 左 右

  1. 从根节点开始遍历入栈,然后依次让右节点进栈、左节点进栈,这样出栈的时候就是先左后右了(符合前序的中左右)。
  2. 每次出栈,就写入返回数组中,然后将该节点的右节点进栈、左节点进栈…
  3. 直到栈被取空了,就代表遍历完所有节点了。

Go代码

func preorderTraversal(root *TreeNode) []int {
    if root == nil {
        return nil
    }
    ret_arr := make([]int, 0)
    stack := []*TreeNode{root}
    for len(stack)!= 0 {
        popNode := stack[len(stack)-1]
        stack = stack[:len(stack)-1]
        ret_arr = append(ret_arr, popNode.Val)
        if popNode.Right != nil {
            stack = append(stack, popNode.Right)
        }
        if popNode.Left != nil {
            stack = append(stack, popNode.Left)
        }
    }
    return ret_arr
}

迭代实现二叉树的后序遍历

题目链接:LeetCode-145. 二叉树的后序遍历

思路分析:栈+反转数组

后序遍历:左 右 中

  1. 我们可以将前序遍历的右左入栈反过来,就变成了中右左的遍历方式
  2. 中右左反转就是左右中,所以反转后就变成后序遍历的结果了。

Go代码

func postorderTraversal(root *TreeNode) []int {
    if root == nil {
        return nil
    }
    ret_arr := make([]int, 0)
    stack := []*TreeNode{root}
    for len(stack)!= 0 {
        // 从栈出一个节点
        popNode := stack[len(stack)-1]
        stack = stack[:len(stack)-1]
        ret_arr = append(ret_arr, popNode.Val)
        if popNode.Left != nil {
            stack = append(stack, popNode.Left)
        }
        if popNode.Right != nil {
            stack = append(stack, popNode.Right)
        }
    }
    // 反转
    for i,j:=0,len(ret_arr)-1; i<=j; i,j=i+1,j-1 {
        ret_arr[i], ret_arr[j] = ret_arr[j], ret_arr[i]
    }
    return ret_arr
}

迭代实现二叉树的中序遍历

题目链接:LeetCode-94. 二叉树的中序遍历

思路分析:栈+指针

相信大家看了上面的前序、后序遍历之后,会认为中序遍历也差不多,可以变一变代码顺序(跟递归写法的变换一样)就能完成中序遍历,其实不然,我们没法只根据上面的思路去完成中序遍历!!
因为:前序遍历和中序遍历的遍历顺序和操作顺序是不一致的!!!

在前序遍历中:从根节点开始遍历,也是从跟节点开始操作(写入返回数组中),然后遍历到下一个左节点,同时也操作左节点…也就是遍历跟操作的节点始终一致,写起来也比较顺畅。

而在中序遍历中:从根节点开始遍历,但是我们需要一直遍历到最左的叶子节点,才要开始操作该节点(写入返回数组中),所以需要用一个指针指向我们要操作的节点,操作完了之后让该指针指向其下一个操作节点。

Go代码

func inorderTraversal(root *TreeNode) []int {
    if root == nil {
        return nil
    }
    ret_arr := make([]int, 0)
    stack := make([]*TreeNode, 0)
    // 操作节点指针
    cur := root
    for len(stack) != 0 || cur != nil {
        // 如果左子树存在,一直走到左叶子节点
        for cur != nil {
            stack = append(stack, cur)
            cur = cur.Left
        }
        // 出栈一个元素
        cur = stack[len(stack)-1]
        stack = stack[:len(stack)-1]
        // 入结果数组
        ret_arr = append(ret_arr, cur.Val)
        cur = cur.Right
    }
    return ret_arr
}

你可能感兴趣的:(算法与数据结构,golang,算法,开发语言)