一、中序遍历

前中后序三种遍历方法对于左右结点的遍历顺序都是一样的(先左后右),唯一不同的就是根节点的出现位置。对于中序遍历来说,根结点的遍历位置在中间。

所以中序遍历的顺序:左中右

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实现二叉树递归遍历与非递归遍历的更多相关文章

  1. c/c++二叉树的创建与遍历(非递归遍历左右中,破坏树结构)

    二叉树的创建与遍历(非递归遍历左右中,破坏树结构) 创建 二叉树的递归3种遍历方式: 1,先中心,再左树,再右树 2,先左树,再中心,再右树 3,先左树,再右树,再中心 二叉树的非递归4种遍历方式: ...

  2. 二叉树中序遍历,先序遍历,后序遍历(递归栈,非递归栈,Morris Traversal)

    例题 中序遍历94. Binary Tree Inorder Traversal 先序遍历144. Binary Tree Preorder Traversal 后序遍历145. Binary Tre ...

  3. 左神算法基础班4_1&2实现二叉树的先序、中序、后序遍历,包括递归方式和非递归

    Problem: 实现二叉树的先序.中序.后序遍历,包括递归方式和非递归方式 Solution: 切记递归规则: 先遍历根节点,然后是左孩子,右孩子, 根据不同的打印位置来确定中序.前序.后续遍历. ...

  4. c/c++叉树的创建与遍历(非递归遍历左右中,不破坏树结构)

    二叉树的创建与遍历(非递归遍历左右中,不破坏树结构) 创建 二叉树的递归3种遍历方式: 1,先中心,再左树,再右树 2,先左树,再中心,再右树 3,先左树,再右树,再中心 二叉树的非递归4种遍历方式: ...

  5. JAVA 遍历文件夹下的所有文件(递归调用和非递归调用)

    JAVA 遍历文件夹下的所有文件(递归调用和非递归调用) 1.不使用递归的方法调用. public void traverseFolder1(String path) { int fileNum = ...

  6. [复习] JAVA 遍历目录 (递归调用和非递归)

    JAVA 遍历文件夹下的所有文件(递归调用和非递归调用) 1.不使用递归的方法调用. public void traverseFolder1(String path) { int fileNum = ...

  7. 二叉树遍历(非递归版)——python

    二叉树的遍历分为广度优先遍历和深度优先遍历 广度优先遍历(breadth first traversal):又称层次遍历,从树的根节点(root)开始,从上到下从从左到右遍历整个树的节点. 深度优先遍 ...

  8. C++版 - LeetCode 144. Binary Tree Preorder Traversal (二叉树先根序遍历,非递归)

    144. Binary Tree Preorder Traversal Difficulty: Medium Given a binary tree, return the preorder trav ...

  9. 【python中二叉树的实现】python中二叉树的创建、三种方式递归遍历和非递归遍历

    代码如下: # coding=utf-8 class myNode(object): def __init__(self, data=-1, lchild=None, rchild=None): se ...

随机推荐

  1. linux时间校准 设置时间为上海时区

      [root@localhost log]# rm -f /etc/localtime [root@localhost log]# cp /usr/share/zoneinfo/Asia/Shang ...

  2. centos8使用systemctl管理运行级别

    一,什么是systemd的target? 1,关于systemd/systemctl的相关知识,请移步到这一篇 https://www.cnblogs.com/architectforest/p/12 ...

  3. centos8平台使用ethtool配置网卡

    一,ethtool命令所属的包 [root@centos8 liuhongdi]# whereis ethtool ethtool: /usr/sbin/ethtool /usr/share/man/ ...

  4. docker安装部署neo4j

    docker部署neo4j 环境:ubuntu16.04LTS docker安装 详见:菜鸟教程(docker安装) docker国内镜像源配置 第一步,进入阿里云,登陆后点击左侧的镜像加速,生成自己 ...

  5. C# 判断当前目录是否存在不存在则创建

    /// <summary> /// 判断目录是否存在不存在则创建 /// </summary> /// <param name="Path">& ...

  6. Pytest配置文件声明自定义用例标识

    使用pytest.ini添加自定义用例标识: [pytest] # 1.使用没有注册过的标记抛出错误 addopts = --strict-markers # 2.自定义标记 markers = sm ...

  7. frida框架hook参数获取方法入参模板

    python脚本 # -*- coding: utf-8 -*- import logging import frida import sys logging.basicConfig(level=lo ...

  8. Lock接口示例

    Lock 的挂起 await()  唤醒signal() Lock 简单示例 public class LockDemo { public static void main(String[] args ...

  9. pyqt5安装后 pyqt-tools却无法安装解决方法!

    逛了逛国外论坛 这哥们跟我一样 我一晚上没睡 就为了这个 原来 我的py版本太高级了 我把py3.9卸载了 换上了老旧的3.76版本 成功了

  10. JUC---08ForkJion(分支合并)

    一.什么是ForkJion Fork/Join框架是Java7提供的并行执行任务框架,思想是将大任务分解成小任务,然后小任务又可以继续分解,然后每个小任务分别计算出结果再合并起来,最后将汇总的结果作为 ...