python实现二叉树递归遍历与非递归遍历
一、中序遍历
前中后序三种遍历方法对于左右结点的遍历顺序都是一样的(先左后右),唯一不同的就是根节点的出现位置。对于中序遍历来说,根结点的遍历位置在中间。
所以中序遍历的顺序:左中右
1.1 递归实现
每次递归,只需要判断结点是不是None,否则按照左中右的顺序打印出结点value值。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
res=[]
self.recursive_inorder(root,res)
return res def recursive_inorder(self,root,res):
if root:
self.recursive_inorder(root.left,res)
res.append(root.val)
self.recursive_inorder(root.right,res)
1.2 循环实现
循环比递归要复杂得多,因为你得在一个函数中遍历到所有结点。但是有句话很重要:
对于树的遍历,循环操作基本上要用到栈(stack)这个结构
对于中序遍历的循环实现,每次将当前结点(curr)的左子结点push到栈中,直到当前结点(curr)为None。这时,pop出栈顶的第一个元素,设其为当前结点,并输出该结点的value值,且开始遍历该结点的右子树。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
cur=root
res=[]
s=[]
while cur or len(s)!=0:
while cur:
s.append(cur)
cur=cur.left
if len(s)!=0:
cur=s.pop()
res.append(cur.val)
cur=cur.right
return res
二、前序遍历
按照上面的说法,前序遍历指根结点在最前面输出,所以前序遍历的顺序是:中左右
后序遍历指根结点在最后面输出,所以后序遍历的顺序是:左右中
2.1 递归实现
递归实现与中序遍历几乎完全一样,改变一下打印的顺序即可:
class Solution:
def preorderTraversal(self, root): ##前序遍历
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
return [root.val] + self.inorderTraversal(root.left) + self.inorderTraversal(root.right)
2.2 循环实现
仍然使用栈stack,由于前序遍历的顺序是中左右,所以我们每次先打印当前结点curr,并将右子结点push到栈中,然后将左子结点设为当前结点。入栈和出栈条件(当前结点curr不为None时,每一次循环将当前结点curr入栈;当前结点curr为None时,则出栈一个结点)以及循环结束条件(整个循环在stack和curr皆为None的时候结束)与中序遍历一模一样。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
cur=root
res=[]
s=[]
while cur or len(s)!=0:
while cur:
res.append(cur.val)
s.append(cur)
cur=cur.left
if len(s)!=0:
cur=s.pop()
cur=cur.right
return res
三、后序遍历
3.1 递归实现
后序遍历指根结点在最后面输出,所以后序遍历的顺序是:左右中
def postorderTraversal(self, root): ##后序遍历
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
return self.inorderTraversal(root.left) + self.inorderTraversal(root.right) + [root.val]
3.2 循环实现
后序遍历中要保证左孩子和右孩子都已经被访问过并且左孩子在右孩子之前访问才能访问根节点。
要保证根节点在左右子树访问之后才能访问因此对于任意节点cur,先将其入栈。
1、如果cur不存在左孩子和右孩子则直接访问。
2、如果cur存在左孩子或者右孩子,但是左孩子或右孩子都已经被访问过了。
同样可以访问该节点,所以可以引入一个pre节点,存储前一次访问的节点。
如果不是上面的两种情况,则将cur的右孩子入栈
再将cur的左孩子入栈(一定要现将右孩子入栈)
python实现二叉树递归遍历与非递归遍历的更多相关文章
- c/c++二叉树的创建与遍历(非递归遍历左右中,破坏树结构)
		
二叉树的创建与遍历(非递归遍历左右中,破坏树结构) 创建 二叉树的递归3种遍历方式: 1,先中心,再左树,再右树 2,先左树,再中心,再右树 3,先左树,再右树,再中心 二叉树的非递归4种遍历方式: ...
 - 二叉树中序遍历,先序遍历,后序遍历(递归栈,非递归栈,Morris Traversal)
		
例题 中序遍历94. Binary Tree Inorder Traversal 先序遍历144. Binary Tree Preorder Traversal 后序遍历145. Binary Tre ...
 - 左神算法基础班4_1&2实现二叉树的先序、中序、后序遍历,包括递归方式和非递归
		
Problem: 实现二叉树的先序.中序.后序遍历,包括递归方式和非递归方式 Solution: 切记递归规则: 先遍历根节点,然后是左孩子,右孩子, 根据不同的打印位置来确定中序.前序.后续遍历. ...
 - c/c++叉树的创建与遍历(非递归遍历左右中,不破坏树结构)
		
二叉树的创建与遍历(非递归遍历左右中,不破坏树结构) 创建 二叉树的递归3种遍历方式: 1,先中心,再左树,再右树 2,先左树,再中心,再右树 3,先左树,再右树,再中心 二叉树的非递归4种遍历方式: ...
 - JAVA 遍历文件夹下的所有文件(递归调用和非递归调用)
		
JAVA 遍历文件夹下的所有文件(递归调用和非递归调用) 1.不使用递归的方法调用. public void traverseFolder1(String path) { int fileNum = ...
 - [复习] JAVA 遍历目录 (递归调用和非递归)
		
JAVA 遍历文件夹下的所有文件(递归调用和非递归调用) 1.不使用递归的方法调用. public void traverseFolder1(String path) { int fileNum = ...
 - 二叉树遍历(非递归版)——python
		
二叉树的遍历分为广度优先遍历和深度优先遍历 广度优先遍历(breadth first traversal):又称层次遍历,从树的根节点(root)开始,从上到下从从左到右遍历整个树的节点. 深度优先遍 ...
 - C++版 - LeetCode 144. Binary Tree Preorder Traversal (二叉树先根序遍历,非递归)
		
144. Binary Tree Preorder Traversal Difficulty: Medium Given a binary tree, return the preorder trav ...
 - 【python中二叉树的实现】python中二叉树的创建、三种方式递归遍历和非递归遍历
		
代码如下: # coding=utf-8 class myNode(object): def __init__(self, data=-1, lchild=None, rchild=None): se ...
 
随机推荐
- 【python】python返回结果多了none(递归时)
			
把每个返回值的print使用return替代即可 例子: def trim(s): if s[:1]==" ": s=s[1:] retrim(s) elif s[-1:]==&q ...
 - 【C语言程序设计】小游戏之俄罗斯方块(二)!适合初学者上手、练手!
			
第二篇,主要实现俄罗斯方块中的主体部分,包括容器的数据结构以及容器的相关操作,特别是大方块和容器之间的交互逻辑,包括碰撞检测,消除检测等等. 1. 容器的表示 大方块的实现涉及到位运算,而容器同样如此 ...
 - spring boot:使用log4j2做异步日志打印(spring boot 2.3.1)
			
一,为什么要使用log4j2? log4j2是log4j的升级版, 升级后更有优势: 性能更强/吞吐量大/支持异步 功能扩展/支持插件/支持自定义级别等 这些优 ...
 - HTTP协议和APACHE
			
HTTP服务 超文本传输协议. 互联网上应用最广的一种服务. 是一种应用层协议. Internet 互联网表示把各个网连起来 ARPAnet军网 TCP/IP协议 开放的协议 互联互通 Interne ...
 - CPU:Central Processing Unit
			
CPU执行计算任务时都需要遵从一定的规范,程序在被执行前都需要先翻译为CPU可以理解的语言.这种规范或语言就是指令集(ISA,Instruction Set Architecture). CPU 架构 ...
 - drf (学习第三部)
			
目录 视图 视图额基类 视图类扩展 GenericAPIView的视图子类 视图集ViewSet 路由Routers 视图 Django REST framework 提供的视图的主要作用: 控制序列 ...
 - .Net Core 3.1.2 区域路由配置【原创】
			
昨天遇到一个项目问题,新建的.NET core矿建在新建区域的MVC页面里面,无法通过路由找到页面.然后在网络上查询很多资料,发现都是千古文章一大抄,而且都是错误的. 后面又添加了3个专业技术群,同样 ...
 - Phoenix创建索引源码过程
			
date: 2020-09-27 13:50:00 updated: 2020-09-28 16:30:00 Phoenix创建索引源码过程 org.apache.phoenix.index.Inde ...
 - drf 视图使用及源码分析
			
前言 drf视图的源码非常的绕,但是实现的功能却非常的神奇. 它能够帮你快速的解决ORM增删改查的重复代码,非常的方便好用. 下面是它源码中的一句话: class ViewSetMixin: &quo ...
 - Hive 如何快速拉取大批量数据
			
用hive来做数仓类操作,或者大数据的运算,是没有疑问的,至少在你没有更多选择之前. 当我们要hive来做类似于大批量数据的select时,也许问题就会发生了变化. 1. 通用解决方案之分页 首先,我 ...