【leetcode系列】【算法】【中等】二叉树的中序遍历(递归,栈,莫里斯morris)

本文主要是介绍【leetcode系列】【算法】【中等】二叉树的中序遍历(递归,栈,莫里斯morris),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

 

题目:

解题思路:

方法一:递归(时间O(N),空间O(N))

方法二:栈(时间O(N),空间O(N))

方法三:莫里斯遍历(时间O(N),空间O(1))

解题思路:

方法一:递归

方法二:栈

方法三:莫里斯


题目:

题目链接: https://leetcode-cn.com/problems/binary-tree-inorder-traversal/

 

解题思路:

方法一:递归(时间O(N),空间O(N))

每次递归,如果有左子树,就继续使用左子树继续递归

如果没有左子树,就将当前值加入到结果集中,返回到上一层递归中

在上一层递归中,先将当前值加入到结果集中,继续判断是否有右子树

如果有右子树,继续使用右子树递归,如果没有右子树,继续返回上一层递归,重复此逻辑

 

方法二:栈(时间O(N),空间O(N))

先将根节点入栈,开始遍历

只要栈不为空,就从栈中获取栈顶的元素,并判断是否有左子树

如果有左子树,将左子树入栈,然后继续遍历;下次遍历获取到的栈顶元素,为本次遍历入栈的左子树

如果没没有左子树,将当前值加入到结果集中,并将栈顶子树出栈

继续从栈顶获取子树,并将栈顶子树出栈,将值加入到结果集中,然后判断是否有右子树

如果有右子树,则将右子树出栈,继续大循环;如果没有右子树,则继续小循环,获取栈顶元素

图示如下:

将根节点入栈

将1的左子树2入栈

将2的左子树4入栈

因为4没有左子树,将4出栈,并将4加入到结果集res中

因为4没有右子树,所以继续将栈顶元素2出栈,并加入到结果集res中

因为2有右子树,所以不继续从栈顶获取元素,而将2的右子树5入栈

5的情况与4相同,将5出栈,加入到结果集中

从栈顶将1出栈,加入到结果集中

因为1有右子树,所以将1的右子树3入栈

因为3没有左子树,将栈顶元素3出栈,加入到结果集

将3的右子树入栈

将6出栈,加入到结果集中

栈中没有元素,停止遍历,返回结果

 

方法三:莫里斯遍历(时间O(N),空间O(1))

逻辑大致如下:

变量:

  1. root:树的根节点
  2. curr:当前遍历到的节点,初始化为root
  3. prev:辅助节点,初始化为空

流程:

  1. 如果curr左子树为空,则将curr值加入到结果集中,并开始遍历curr的右子树
  2. 如果curr左子树不为空,则进行下记操作:
    1. prev从curr左子树的右子树开始遍历,直到没有右子树,或者遍历到curr节点
    2. 如果prev右子树为空,则将prev右子树指向curr
    3. 如果prev右子树不为空,则将curr.val加入到结果集,更新curr = curr.right右子树,prev = None,继续遍历

图示:

假设一个树原始结构如下:

黑色节点永远为原始root节点,此时将curr指向root节点,curr节点左子树为2,不为空,此时将prev指向2,开始从2的右子树5遍历:

当搜索到8时,因为8没有右子树,停止搜索,此时三个节点情况如下(curr、root都在1位置):

此时,将prev的右子树指向curr,更新curr = curr.left,此时的节点位置和连接情况如下(实线为原始树结构,虚线为新加的连接):

继续循环,此时prev = 2的左子树不为空,继续将prev指向curr的左子树,开始搜索:

4没有右子树,所以直接退出搜索,继续将prev的右子树指向curr,更新curr = curr.left,此时节点位置和链接情况如下(因为prev指向4后,没有向右子树遍历,所以此时prev和curr在同一位置):

此时继续遍历时,发现curr没有左子树,所以将curr的值加入到结果集res中,通过虚线,更新curr = curr.right,开始下次循环。此时curr = 2,所以prev = curr.left继续从2的左子树4开始搜索,4的右节点为2,符合了curr = prev的条件,搜索停止,此时情况如下:

搜索停止时,prev = 4的右子树不为空,所以此时将2加入到结果集中,更新curr = curr.right,删除掉之前多添加出来的连接,即更新prev.right = None,继续循环:

之后逻辑与上述相同,图示流程如下:

 

解题思路:

方法一:递归

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = Noneclass Solution:def inorderTraversal(self, root: TreeNode) -> List[int]:def order_help(node, res):if node and node.left:order_help(node.left, res)if node:res.append(node.val)if node and node.right:order_help(node.right, res)res = []order_help(root, res)return res

 

方法二:栈

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = Noneclass Solution:def inorderTraversal(self, root: TreeNode) -> List[int]:if not root:return []node_stack = [root]res = []while 0 < len(node_stack):if node_stack[-1].left:node_stack.append(node_stack[-1].left)continuewhile 0 < len(node_stack):last_node = node_stack[-1]node_stack.pop()res.append(last_node.val)if last_node.right:node_stack.append(last_node.right)breakreturn res

 

方法三:莫里斯

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = Noneclass Solution:def inorderTraversal(self, root: TreeNode) -> List[int]:curr = rootprev = Noneres = []while curr:if not curr.left:res.append(curr.val)curr = curr.rightelse:prev = curr.leftwhile prev.right and prev.right != curr:prev = prev.rightif not prev.right:prev.right = currcurr = curr.leftelse:res.append(curr.val)prev.right = Nonecurr = curr.rightreturn res

 

这篇关于【leetcode系列】【算法】【中等】二叉树的中序遍历(递归,栈,莫里斯morris)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/633146

相关文章

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

C语言函数递归实际应用举例详解

《C语言函数递归实际应用举例详解》程序调用自身的编程技巧称为递归,递归做为一种算法在程序设计语言中广泛应用,:本文主要介绍C语言函数递归实际应用举例的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录前言一、递归的概念与思想二、递归的限制条件 三、递归的实际应用举例(一)求 n 的阶乘(二)顺序打印

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

Jackson库进行JSON 序列化时遇到了无限递归(Infinite Recursion)的问题及解决方案

《Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursion)的问题及解决方案》使用Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursi... 目录解决方案‌1. 使用 @jsonIgnore 忽略一个方向的引用2. 使用 @JsonManagedR

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

Rust中的BoxT之堆上的数据与递归类型详解

《Rust中的BoxT之堆上的数据与递归类型详解》本文介绍了Rust中的BoxT类型,包括其在堆与栈之间的内存分配,性能优势,以及如何利用BoxT来实现递归类型和处理大小未知类型,通过BoxT,Rus... 目录1. Box<T> 的基础知识1.1 堆与栈的分工1.2 性能优势2.1 递归类型的问题2.2

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1