LeetCode 94 | 基础题,如何不用递归中序遍历二叉树?
今天是LeetCode专题第60篇文章,我们一起来看的是LeetCode的94题,二叉树的中序遍历。
这道题的官方难度是Medium,点赞3304,反对只有140,通过率有63.2%,在Medium的题目当中算是很高的了。这题非常基础,可以说是程序员必会的算法题之一。
我们先来看题意。
题意
题意很短, 只有一句话,给定一棵二叉树,返回它中序遍历的结果。
样例
Input: [1,null,2,3]
1
\
2
/
3
Output: [1,3,2]
用递归做这道题非常简单,你能不用递归实现吗?
题解
我们先来介绍一下二叉树的中序遍历,二叉树有三种遍历方式,分别是先序、中序和后序。对于初学者而言,可能会觉得这三种顺序傻傻分不清楚,不知道它们之间有什么分别。其实说白了非常简单,遍历方式其实指的是我们在递归遍历的时候的选择顺序。
假设我们目前递归到的节点是u,它有左右两个孩子。在保证左孩子一定先于右孩子访问的前提下,我们有三种策略。第一种是先把u加入访问序列,之后再分别遍历左右子树,第二种是先递归遍历左子树,然后把u加入访问序列,最后再遍历右子树。第三种策略是先递归遍历左右子树,最后再把u加入访问序列。
这三种策略之间有什么不同呢?其实最大的不同就在于u加入访问序列的顺序不同,如果是先加入u再访问,那么就是先序。如果是先访问了左子树再来加入u,则是中序,最后如果是先递归了左右子树,最后再加入u,则是后序。说白了也就是u先加入就是先序,中间加入就是中序,最后加入就是后序。如果你还觉得有点蒙的话,我们来看下代码就非常清晰了。
# 先序
def dfs(u):
visited.append(u)
dfs(u.left)
dfs(u.right)
# 中序
def dfs(u):
dfs(u.left)
visited.append(u)
dfs(u.right)
# 后序
def dfs(u):
dfs(u.left)
dfs(u.right)
visited.append(u)
但是题目当中要求我们不通过递归来实现,这该怎么办呢?
其实也有办法,我们需要从递归的实现原理入手。我们知道在编译器内部,当我们从一个函数调用另外一个函数的时候,这些函数的信息会被存储在一个栈结构内。栈中间的每一个节点会记录函数的名称以及它目前运行的位置,以及一些中间变量等等。所以当我们递归的时候,其实就是当前的函数不停的入栈的过程。

比如我们dfs函数在第5行代码处递归调用了dfs函数,那么编译器内部的堆栈会记录[(dfs, 5), (dfs, 1)]。如果我们在dfs的第一行又调用了sum函数,那么编译器又会把sum这个函数加入堆栈,变成:[(dfs, 5), (dfs, 1), (sum, 1)]。当函数执行完成之后,会从栈中弹出。
简而言之,递归其实就是利用编译器自行维护的栈结构来简化我们代码和功能的编写。既然这道题当中要求我们不能使用递归,那么我们就只能自己来使用栈来模拟这个过程了。由于我们自己需要维护栈当中的元素,使得整个过程会稍微复杂一些。
在这道题目当中,我们使用栈来记录树上的节点。栈顶的节点即是当前访问的节点。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
ret = []
stack = []
stack.append(root)
while len(stack) > 0:
# 获取栈顶顶点
cur = stack[-1]
if cur is None:
stack.pop()
continue
# 如果左孩子存在,那么优先遍历左孩子
if cur.left is not None:
stack.append(cur.left)
# 把左指针置为空,防止死循环
# 这里也可以用set来维护
cur.left = None
continue
# 左边遍历结束之后加入序列
ret.append(cur.val)
stack.pop()
if cur.right is not None:
stack.append(cur.right)
return ret
总结
如果只是二叉树的遍历,那这个谁都会,但如果不能使用递归,那么就很考验硬实力了。需要我们对递归的底层原理有深入的理解,并且熟悉栈这个数据结构的使用。这段代码的逻辑不难理解,但实现还是挺锻炼人的,推荐大家试试。
今天的文章到这里就结束了,如果喜欢本文的话,请来一波素质三连,给我一点支持吧(关注、转发、点赞)。

- END -
LeetCode 94 | 基础题,如何不用递归中序遍历二叉树?的更多相关文章
- java创建二叉树并实现非递归中序遍历二叉树
java创建二叉树并递归遍历二叉树前面已有讲解:http://www.cnblogs.com/lixiaolun/p/4658659.html. 在此基础上添加了非递归中序遍历二叉树: 二叉树类的代码 ...
- Leetcode 94. Binary Tree Inorder Traversal (中序遍历二叉树)
Given a binary tree, return the inorder traversal of its nodes' values. For example: Given binary tr ...
- LeetCode OJ:Binary Tree Inorder Traversal(中序遍历二叉树)
Given a binary tree, return the inorder traversal of its nodes' values. For example:Given binary tre ...
- YTU 2346: 中序遍历二叉树
原文链接:https://www.dreamwings.cn/ytu2346/2606.html 2346: 中序遍历二叉树 时间限制: 1 Sec 内存限制: 128 MB 提交: 12 解决: ...
- Binary Tree Inorder Traversal-非递归实现中序遍历二叉树
题目描述: 给定一颗二叉树,使用非递归方法实现二叉树的中序遍历 题目来源: http://oj.leetcode.com/problems/binary-tree-inorder-traversal/ ...
- Leetcode(105)-从前序与中序遍历序列构造二叉树
根据一棵树的前序遍历与中序遍历构造二叉树. 注意:你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15, ...
- 094 Binary Tree Inorder Traversal 中序遍历二叉树
给定一个二叉树,返回其中序遍历.例如:给定二叉树 [1,null,2,3], 1 \ 2 / 3返回 [1,3,2].说明: 递归算法很简单,你可以通过迭代算法完成吗?详见 ...
- LeetCode:二叉树的非递归中序遍历
第一次动手写二叉树的,有点小激动,64行的if花了点时间,上传leetcode一次点亮~~~ /* inorder traversal binary tree */ #include <stdi ...
- java建立二叉树,递归/非递归先序遍历,递归/非递归中序遍历,层次遍历
import java.util.LinkedList; import java.util.Scanner; import java.util.Stack; //structure of binary ...
随机推荐
- 2020牛客暑假多校训练营 第二场 G Greater and Greater bitset
LINK:Greater and Greater 确实没能想到做法. 考虑利用bitset解决问题. 做法是:逐位判断每一位是否合法 第一位 就是 bitset上所有大于\(b_1\)的位置 置为1. ...
- 6.10 省选模拟赛 小C的利是 高斯消元 矩阵行列式
LINK:小C的利是 想起来把这道题的题解写了 .一个常识:利是在广东那边叫做红包. 关于行列式的题目 不过我不太会23333..口胡还是可以的. 容易想到10分的状压.不过没什么意思. 仔细观察要求 ...
- 华为云GaussDB(DWS)内存知识点,你知道吗?
前言 在日常数据库的使用中,难免会遇到一些内存问题.此次博文主要向大家分享一些华为云数仓GaussDB(DWS)内存的基本框架以及基本视图的使用,以便遇到内存问题后可以有一个基本的判断. 注意,本篇博 ...
- 微信公众号如何将PDF上传到公众号?
微信公众号如何将PDF上? 我们都知道创建一个微信公众号,在公众号中发布一些文章是非常简单的,但公众号添加附件下载的功能却被限制,如今可以使用小程序“微附件”进行在公众号中添加附件. 以下是公众号添加 ...
- ROS 八叉树地图构建 - 使用 octomap_server 建图过程总结!
构建语义地图时,最开始用的是 octomap_server,后面换成了 semantic_slam: octomap_generator,不过还是整理下之前的学习笔记. 一.增量构建八叉树地图步骤 为 ...
- C++游戏(大型PC端枪战游戏)服务器架构
实习期间深入参与到某大型pc端枪战游戏的后端开发中,此游戏由著名游戏工作室编写,代码可读性极高,自由时间对游戏后台代码进行了深入研究,在满足自身工作需要的同时对游戏后台的架构也有了理解,记录在此,以便 ...
- The Definitive Guide to Ruby's C API The Ruby C API Running Ruby in C Running C in Ruby
最近在研究如何在C/C++中 嵌入ruby脚本,很感谢找到了一篇文章,分享一下. The Definitive Guide to Ruby's C API
- .Net 桌面程序(winform,wpf,跨平台avalonia)打安装包部署到windows 入门
.Net 桌面程序(winform,wpf,跨平台avalonia)部署到windows 入门 本文以为avalonia为例,用Setup Factory 将.Net桌面程序(winform,wpf, ...
- java.util.Scanner中hasNext()方法和next()方法的区别
先说结论: 两者均根据空格划分数据 两者在没有数据输入时均会等待输入 next()方法会将空格划分的数据依次输出,运行一次,输出一个 hasNext()方法会跟着next()方法移动,当前数据不为空, ...
- ES6系列之项目中常用的新特性
ES6系列之项目中常用的新特性 ES6常用特性 平时项目开发中灵活运用ES6+语法可以让开发者减少很多开发时间,提高工作效率.ES6版本提供了很多新的特性,接下来我列举项目中常用的ES6+的特性: l ...