【LeetCode 算法专题突破】二叉树的深度优先遍历(⭐)

简介: 【LeetCode 算法专题突破】二叉树的深度优先遍历(⭐)

前言

接下来我要开始攻克二叉树这一个大难题了,我打算把二叉树分成四个部分进行总结:

  1. 二叉树的深度优先遍历
  2. 二叉树的广度优先遍历(也叫层序遍历)
  3. 二叉树的基本属性求解
  4. 二叉树其他相关问题(删改、求公共祖先、二叉搜索树等等)

那我也不废话了,直接开始。

1. 二叉树的前序遍历

接下来,我们就将二叉树的前中后序的递归遍历都做一遍,然后再分别将这四种遍历的迭代实现方法也做一遍,基础不牢,地动山摇,我们慢慢来,一步一个脚印学好二叉树!

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

题目描述

所谓的前中后序遍历,在前中后的是什么?其实就是根节点,所以我一般习惯用一个口诀来记住前中后序的遍历顺序:

  1. 前序就是:根左右
  2. 中序就是:左根右
  3. 后序就是:左右根

这其实就是按照根在遍历中的顺序划分的遍历方式。来看代码:

代码

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func preorderTraversal(root *TreeNode) (res []int) {
    var preorder func(node *TreeNode)
    preorder = func(node *TreeNode) {
        if node == nil {
            return
        }
        res = append(res, node.Val) // 根
        preorder(node.Left)  // 左
        preorder(node.Right) // 右
    }
    preorder(root) // 调用前序遍历
    return res
}

我们来看这个代码,其实这就是一个简单的递归遍历的函数,所谓的 “根左右” 其实就是先把 “根” 位置的值给塞进 res 数组而已。

2. 二叉树的中序遍历

那就继续中序遍历

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

题目描述

其实刚刚已经介绍过前中后序是怎么样的了,所以我们直接看代码:

代码

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func inorderTraversal(root *TreeNode) (res []int) {
    var inorder func(node *TreeNode)
    inorder = func(node *TreeNode) {
        if node == nil {
            return 
        }
        inorder(node.Left)
        res = append(res, node.Val)
        inorder(node.Right)
    }
    inorder(root)
    return res
}

这里我注释也懒得打了,可以发现他其实比起前序遍历就只是改了一个地方的代码,就是把 根 的位置和向左递归的位置换了一下,这就是中序遍历的遍历方法。

3. 二叉树的后序遍历

一做肯定是得做全套滴

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

题目描述

其实现在题目描述也没有什么意义了,知道是后序遍历,我们直接写代码就完了:

代码

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func postorderTraversal(root *TreeNode) (res []int) {
    var postorder func(node *TreeNode) 
    postorder = func(node *TreeNode) {
        if node == nil {
            return 
        }
        postorder(node.Left)
        postorder(node.Right)
        res = append(res, node.Val)
    } 
    postorder(root)
    return res
}

没有意外,也是朴实无华的改个代码的位置。

现在开胃小菜算是做完了,像前中后这样的遍历其实并没有什么难度,所以我们还需要挑战一下前中后序的非递归遍历,不然不能算是真正学会了这三种遍历的方式。既是锻炼我们的代码能力,也是让我们熟悉二叉树的基本遍历方式,打牢基础,后面才不会越看越懵逼。

4. 前序遍历的非递归实现

这里我就不把题目描述给放出来了,这里我们用的就是第一题

代码与思路

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func preorderTraversal(root *TreeNode) (ans []int) {
    if root == nil {
        return
    }
    st := list.New()
    st.PushBack(root)
    for st.Len() > 0 {
        node := st.Remove(st.Back()).(*TreeNode)
        ans = append(ans, node.Val)
        if node.Right != nil {
            st.PushBack(node.Right)
        }
        if node.Left != nil {
            st.PushBack(node.Left)
        }
    }
    return ans
}

我来讲讲使用迭代法求解的一个流程,采取的是用一个栈来模拟递归的方法(这里我采用的是 go 语言的 list 来模拟栈操作),模拟前序遍历 “根左右” 的遍历方式

  1. 首先将根(或者说当前走到的节点)的值存入数组
  2. 然后分别将右节点和左节点入栈,因为出栈的顺序是相反的,所以我们入栈的时候就要这样先入右节点再入左节点,这样出栈遍历的时候就能达成 “根左右” 的遍历方式了

其实核心的步骤就是这两步,那我们继续实现中序的非递归遍历

5. 中序遍历的非递归实现

代码与思路

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func inorderTraversal(root *TreeNode) (ans []int) {
    st := list.New()
    cur := root
    for cur != nil || st.Len() > 0 {
        if cur != nil {
            st.PushBack(cur)
            cur = cur.Left
        } else {
            cur = st.Remove(st.Back()).(*TreeNode)
            ans = append(ans, cur.Val)
            cur = cur.Right
        }
    }
    return ans
}

前序遍历的时候,我们就是不断计算根位置的值,然后只管用栈按顺序遍历二叉树就行了,但是到了中序遍历,我们需要取的是左节点的值,所以我们就需要在左节点遍历的时候边遍历边取值,我们来根据代码梳理一下他的流程

  1. 将当前节点入栈,然后一直往左遍历直到走到 nil
  2. 走到 nil 之后,上一个节点,也就是栈顶的元素就是最左节点,输出到 ans
  3. 然后往右遍历一步,持续这个三步循环

这三步模拟的就是 “左根右” 的遍历方式,刚好也是三步,找到最左,取根,找右,循环往复,就能完成中序遍历了。迭代算法确实不太好想,但是上手模拟一遍还是比较好理解的。

6. 后序遍历的非递归实现

代码与思路

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func postorderTraversal(root *TreeNode) (ans []int) {
    if root == nil {
        return
    }
    st := list.New()
    st.PushBack(root)
    for st.Len() > 0 {
        node := st.Remove(st.Back()).(*TreeNode)
        ans = append(ans, node.Val)
        if node.Left != nil {
            st.PushBack(node.Left)
        }
        if node.Right != nil {
            st.PushBack(node.Right)
        }
    }
    reverse(ans)
    return ans
}
func reverse(a []int) { // 反转数组
    l, r := 0, len(a)-1
    for l < r {
        a[l], a[r] = a[r], a[l]
        l, r = l+1, r-1
    }
}

后序遍历有一个非常巧妙的解法:因为前序遍历是 “根左右”,后续遍历是 “左右根”,如果我们根据 “根右左” 的顺序来进行遍历,然后再将结果进行反转就能将 “根右左” -> “左右根”,这样就完成了后续遍历,也就是我们只需要修改一下前序遍历的代码即可

就那上述代码来说,我将遍历左右的顺序进行了调换,然后实现了一个 reverse 反转数组(go 语言没有 C++ 那样提供 STL,难受)按照刚刚分析出来的思路实现后序遍历。

总结

基础不牢,地动山摇,把二叉树的前中后序学会,我们下一节挑战二叉树的广度优先遍历,又或者说,二叉树的层序遍历。

相关文章
|
2月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
46 0
|
1月前
|
算法
分享一些提高二叉树遍历算法效率的代码示例
这只是简单的示例代码,实际应用中可能还需要根据具体需求进行更多的优化和处理。你可以根据自己的需求对代码进行修改和扩展。
|
1月前
|
存储 缓存 算法
如何提高二叉树遍历算法的效率?
选择合适的遍历算法,如按层次遍历树时使用广度优先搜索(BFS),中序遍历二叉搜索树以获得有序序列。优化数据结构,如使用线索二叉树减少空指针判断,自定义节点类增加辅助信息。利用递归与非递归的特点,避免栈溢出问题。多线程并行遍历提高速度,注意线程安全。缓存中间结果,避免重复计算。预先计算并存储信息,提高遍历效率。综合运用这些方法,提高二叉树遍历算法的效率。
62 5
|
1月前
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
|
1月前
|
算法
树的遍历算法有哪些?
不同的遍历算法适用于不同的应用场景。深度优先搜索常用于搜索、路径查找等问题;广度优先搜索则在图的最短路径、层次相关的问题中较为常用;而二叉搜索树的遍历在数据排序、查找等方面有重要应用。
39 2
|
1月前
|
机器学习/深度学习 JSON 算法
二叉树遍历算法的应用场景有哪些?
【10月更文挑战第29天】二叉树遍历算法作为一种基础而重要的算法,在许多领域都有着不可或缺的应用,它为解决各种复杂的问题提供了有效的手段和思路。随着计算机科学的不断发展,二叉树遍历算法也在不断地被优化和扩展,以适应新的应用场景和需求。
48 0
|
2月前
|
算法
每日一道算法题(Leetcode 20)
每日一道算法题(Leetcode 20)
35 2
|
2月前
|
存储 算法
数据结构与算法学习十六:树的知识、二叉树、二叉树的遍历(前序、中序、后序、层次)、二叉树的查找(前序、中序、后序、层次)、二叉树的删除
这篇文章主要介绍了树和二叉树的基础知识,包括树的存储方式、二叉树的定义、遍历方法(前序、中序、后序、层次遍历),以及二叉树的查找和删除操作。
34 0
|
2月前
【LeetCode 37】106.从中序与后序遍历构造二叉树
【LeetCode 37】106.从中序与后序遍历构造二叉树
25 0
|
3天前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
110 80

热门文章

最新文章