美文网首页
二叉树遍历

二叉树遍历

作者: 失眠是真滴难受 | 来源:发表于2020-10-09 17:15 被阅读0次

以前在数据结构的书上学过二叉树的遍历,老师讲了前序、中序、后序遍历三种,但是只是讲了一下概念,在纸上画一下遍历的过程,并没有讲代码的实现。

算法思想

先序遍历

前序遍历的顺序是 根节点-左子树-右子树 。意思是从根节点开始,要一直访问左子树,直到没有左孩子,然后访问右子树。

前序遍历
(图片来自知乎)

理解起来应该是很简单的,不过实现起来就不一样了,图中演示的是用递归的方式遍历的,事实上还可以用迭代来实现,也就是 DFS 和 BFS。

中序遍历

中序遍历

后序遍历

在这个算法演示 的网站上没有找到后序遍历的图,后序遍历的过程就是 左子树-右子树-根节点。

定义树的结构,以下使用的是 golang

type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

DFS实现

在遍历二叉树之前先要生成一棵二叉树,可以看到,生成二叉树的过程也是递归的,并且类似这样的代码在很多与二叉树有关的地方都能用到,也可以叫做模板。

递归生成二叉树

package main

import "fmt"

type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

func main() {
    root := &TreeNode{}
    dfs(root, 1)
    fmt.Println(root.Left)

}

func dfs(p *TreeNode, depth int) {
    if depth < 3 {
        left := &TreeNode{Val: 2 * depth}
        right := &TreeNode{Val: 4 * depth}
        p.Left = left
        p.Right = right
        dfs(p.Left, depth+1)
        dfs(p.Right, depth+1)
    }
}

接下来才是遍历二叉树

func dfsbr(p *TreeNode, res *[]int) {
    if p != nil {
        *res = append(*res, p.Val)
        dfsbr(p.Left, res)
        dfsbr(p.Right, res)
    }
}

先访问左孩子节点,再访问右孩子节点,这就是先序遍历了。看一下打印出来的结果

$ go run main.go
[0 2 4 8 4 4 8]
binary

注意,golang 在root 初始化的时候会默认给 root 赋值,Val 的类型为 int ,因此初值为 0。对比一下二叉树和打印出来的节点,是符合 根节点-左子树-右子树 这个过程的。

关于后序遍历和中序遍历的递归实现其实是一样的,只是把递归的顺序变换了一下而已。

中序遍历

func dfsbr(p *TreeNode, res *[]int) {
    if p != nil {
        dfsbr(p.Left, res)
        *res = append(*res, p.Val)
        dfsbr(p.Right, res)
    }
}

后序遍历

func dfsbr(p *TreeNode, res *[]int) {
    if p != nil {
        dfsbr(p.Left, res)
        dfsbr(p.Right, res)
        *res = append(*res, p.Val)
    }
}

BFS实现

在 DFS 中,是使用的递归的方式查找,程序运行过程中的数据会保存在系统栈里。而使用 BFS 需要自己创建一个队列,保存程序运行中途的信息。

层序遍历

func bfs(p *TreeNode) []int {
    res := make([]int, 0)
    if p == nil {
        return res
    }
    queue := []*TreeNode{p}
    for len(queue) > 0 {
        length := len(queue)
        for length > 0 {
            length--
            if queue[0].Left != nil {
                queue = append(queue, queue[0].Left)
            }
            if queue[0].Right != nil {
                queue = append(queue, queue[0].Right)
            }
            res = append(res, queue[0].Val)
            queue = queue[1:]
        }
    }
    return res
}

打印结果

$ go run main.go 
[0 2 4 4 8 4 8]

可以看到,层序遍历的结果和上图中画出来的二叉树是一一对应的。

先序遍历

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func preorderTraversal(root *TreeNode) []int {
    result := make([]int, 0)

    if root == nil {
        return result
    }

    queue := make([]*TreeNode, 0)

    for len(queue) > 0 || root != nil {
        for root != nil {
            result = append(result, root.Val)
            queue = append(queue, root)
            root = root.Left
        }
        root = queue[len(queue) - 1].Right
        queue = queue[:len(queue) - 1]
    }
    return result
}

中序遍历

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func inorderTraversal(root *TreeNode) []int {
    result := make([]int, 0)
    
    if root == nil {
        return result
    }

    queue := make([]*TreeNode, 0)
    
    for len(queue) > 0 || root != nil {
        for root != nil {
            queue = append(queue, root)
            root = root.Left
        }

        node := queue[len(queue) - 1]
        queue = queue[:len(queue) - 1]
        result = append(result, node.Val)
        root = node.Right
    }
    return result
}

后序遍历

func postorderTraversal(root *TreeNode) []int {
    result := make([]int, 0)

    if root == nil {
        return result
    }

    queue := make([]*TreeNode, 0)
    var lastVisited *TreeNode

    for len(queue) > 0 || root != nil{
        for root != nil {
            queue = append(queue, root)
            root = root.Left
        }
        n := queue[len(queue) - 1]    
        if n.Right == nil || n.Right == lastVisited {
            result = append(result, n.Val)
            queue = queue[:len(queue) - 1]
            lastVisited = n
        } else {
            root = n.Right
        }
    }

    return result
}

公众号:没有梦想的阿巧 后台回复 "群聊",一起学习,一起进步

相关文章

  • 二叉树 基础操作

    二叉树的使用 二叉树结构 先序创建二叉树 DFS 先序遍历二叉树 中序遍历二叉树 后序遍历二叉树 BFS 层次遍历...

  • 关于二叉树的算法题

    前序遍历中序遍历后序遍历判断是否是平衡二叉树判断是否是对称二叉树判断二叉树高度按照层遍历二叉树判断二叉树宽度

  • 二叉树遍历

    二叉树 二叉树的存储结构 前序遍历 中序遍历 后序遍历 遍历代码 反转二叉树 深入学习二叉树 二叉树-你必须要懂!...

  • 二叉树操作

    树节点 逐行顺序解析二叉树 前序遍历二叉树 中序遍历二叉树 后序遍历二叉树 删除指定数值的节点 前序遍历顺序存储的...

  • 数据结构与算法之二叉树遍历(七)

    目录 前序遍历中序遍历后序遍历层序遍历遍历方式的选择条件根据遍历结果重构二叉树翻转二叉树计算二叉树的高度判断一棵树...

  • 二叉树三种遍历Swift代码实现

    二叉树的三种遍历 二叉树 前序遍历 中序遍历 后序遍历 另外 不得不说,得到二叉树的前序遍历和中序遍历的结果或者后...

  • 二叉树的遍历

    二叉树的遍历 二叉树遍历 分为前序遍历、中序遍历和后序遍历。 前序遍历 (DLR) 先访问根节点,然后前序遍历左子...

  • 前端二叉树

    (一)构造二叉树 (二)中序遍历 (三)前序遍历 前序遍历可以复制二叉树,效率比重新构造二叉树高 (四)后序遍历 ...

  • 数据结构:树的实现和遍历(c++)

    (一)二叉树的遍历——递归实现 二叉树常见的遍历方式分为前序遍历、中序遍历和后序遍历。 1 前序遍历 前序遍历也叫...

  • leetcode 144 145 94

    二叉树遍历 前序遍历 中序遍历 后序遍历

网友评论

      本文标题:二叉树遍历

      本文链接:https://www.haomeiwen.com/subject/hxalpktx.html