多种方法实现二叉树的先序、中序、后序、层序遍历

文章目录

  • 为什么需要会这个?
  • 先序、中序、后序遍历
    • 先序遍历
    • 中序遍历
    • 后序遍历
  • 层序遍历

为什么需要会这个?

在面试的时候,经常会被问到各种和二叉树相关的问题,而和二叉树相关的问题,一般要和二叉树中的遍历方式结合起来。二叉树中最重要的几种遍历方式包括先序遍历、中序遍历、后序遍历和层序遍历。

其中先序遍历、中序遍历以及后序遍历可以有多种实现方式

  • DFS深度优先搜索。这种方式又叫做Traverse,使用一个全局变量来记录整个二叉搜索树的结果,递归函数里面没有返回值
  • 分治算法。分治算法也可以用递归来实现,递归函数有返回值,在二叉树中,一般为左子树的部分解,或者右子树的部分解,在当前root节点中,会将左右子树的结果进行组合,生成当前子树解。
  • 非递归算法,需要用一个stack和一个cur指针用来模拟整个先序、中序、后序的过程

分治算法和DFS搜索算法,都依赖于递归的程序结构。但二者有些许不同

  • 分治算法,在二叉树的问题中,应用极多,可以解决很多问题。如果当前问题可以分解为左子树问题的解,右子树问题的解,通过一定的规则,能够让左右子树组合的解变成当前子树的解。那么就可以用分治算法来解决该问题
  • DFS算法。会从根节点开始遍历节点,到达叶子节点之后,返回上一层。这种方法需要用一个全局变量来记录解

先序、中序、后序遍历

先序遍历

分治算法实现

func preorderTraversal(root *TreeNode) []int {
    if root == nil {
        return []int{}
    }
    left := preorderTraversal(root.Left)
    right := preorderTraversal(root.Right)
    res := append([]int{},root.Val)
    res = append(res,left...)
    res = append(res,right...)
    return res 
}

DFS算法实现

func preorderTraversal(root *TreeNode) []int {
    if root == nil {
        return []int{}
    }
    var res []int 
    dfs(root,&res)
    return res 
}

func dfs(root *TreeNode,res *[]int){
    if root == nil{
        return 
    }
    *res = append(*res,root.Val)
    dfs(root.Left,res)
    dfs(root.Right,res)
}

非递归实现

func preorderTraversal(root *TreeNode) []int {
    if root == nil{
        return []int{}
    }
    var preorder []int 
    cur := root 
    var stack []*TreeNode
    for ;cur!=nil || len(stack)>0;{
        fmt.Println(cur.Val,len(stack))
        for ;cur!=nil;{
            stack = append(stack,cur)
            preorder = append(preorder,cur.Val)
            cur = cur.Left 
        }
        cur = stack[len(stack)-1]
        stack = stack[:len(stack)-1]
    }
    return preorder
}

中序遍历

分治算法实现

func inorderTraversal(root *TreeNode) []int {
    if root == nil{
        return []int{}
    }
    left := inorderTraversal(root.Left)
    right := inorderTraversal(root.Right)
    var res []int 
    res = append(res,left...)
    res = append(res,root.Val)
    res = append(res,right...)
    return res 
}

DFS算法实现

func inorderTraversal(root *TreeNode) []int {
    var res []int 
    dfs(root,&res)
    return res 
}


func dfs(root *TreeNode,res *[]int){
    if root == nil{
        return 
    }
    dfs(root.Left,res)
    *res = append(*res,root.Val)
    dfs(root.Right,res)
}

非递归算法实现

func inorderTraversal(root *TreeNode) []int {
    var res []int 
    var stack []*TreeNode
    for cur:=root;cur!=nil||len(stack)>0;{
        for ;cur!=nil;{
            stack = append(stack,cur)
            cur = cur.Left
        }
        cur = stack[len(stack)-1]
        res = append(res,cur.Val)
        stack = stack[:len(stack)-1]
        cur = cur.Right
    }
    return res 
}

后序遍历

分治算法实现

func postorderTraversal(root *TreeNode) []int {
    if root == nil{
        return []int{}
    }

    var res []int 
    left := postorderTraversal(root.Left)
    right := postorderTraversal(root.Right)
    res = append(res,left...)
    res = append(res,right...)
    res = append(res,root.Val)
    return res 
}

DFS算法实现

func postorderTraversal(root *TreeNode) []int {
    var res []int 
    dfs(root,&res)
    return res 
}

func dfs(root *TreeNode,res *[]int){
    if root == nil{
        return 
    }
    dfs(root.Left,res)
    dfs(root.Right,res)
    *res = append(*res,root.Val)
}

非递归实现

后序遍历非递归的实现,实际上用了一个比较取巧的方法,通过内容来实现

func postorderTraversal(root *TreeNode) []int {
    var res []int
    var stack []*TreeNode
    for cur:=root;cur!=nil || len(stack)>0;{
        for ;cur!=nil;{
            stack = append(stack,cur)
            res = append(res,cur.Val)
            cur = cur.Right
        }
        cur = stack[len(stack)-1]
        cur = cur.Left 
        stack = stack[:len(stack)-1]        
    }

    reverse(res)
    return res 
}

func reverse(slice []int){
    for l,r:=0,len(slice)-1;l<r;l,r=l+1,r-1{
        slice[l],slice[r] = slice[r],slice[l]
    }
}

层序遍历

使用一个队列

func levelOrder(root *TreeNode) [][]int {
    var res [][]int 
    if root == nil{
        return res 
    }
    queue := []*TreeNode{root}
    for ;len(queue) > 0;{
        var curLevel []int 
        l := len(queue)
        for i:=0;i<l;i++{
            cur := queue[0]
            curLevel = append(curLevel,queue[0].Val)
            queue = queue[1:]
            if cur.Left !=nil{
                queue = append(queue,cur.Left)
            }
            if cur.Right != nil{
                queue = append(queue,cur.Right)
            }
        }
        res = append(res,curLevel)
    }
    return res 
}

使用交替的数组

func levelOrder(root *TreeNode) [][]int {
    if root == nil{
        return [][]int{}
    }
    res := [][]int{}
    curLevel := []*TreeNode{root}
    for len(curLevel)!=0 {
        nextLevel :=[]*TreeNode{}
        //get cur level val and next level node 
        curLevelVal := []int{}
        for _,node := range curLevel{
            curLevelVal = append(curLevelVal,node.Val)
            if node.Left!=nil {
                nextLevel = append(nextLevel,node.Left)
            }
            if node.Right != nil{
                nextLevel = append(nextLevel,node.Right)
            }   
        }
        res = append(res,curLevelVal)
        curLevel = nextLevel
    }
    return res 
}

你可能感兴趣的:(算法技巧总结,算法规律模板)