文章目录

  • 前言
  • 一、用递归法实现遍历
    • 1.1 前序遍历
    • 1.2 中序遍历
    • 1.3 后序遍历
  • 二、用迭代法实现遍历
    • 2.1 前序遍历
    • 2.2 中序遍历
    • 2.3 后序遍历
      • 2.3.1 后序解法一
      • 2.3.2 后序解法二
  • 三、测试验证

前言

本文主要记录二叉树的遍历方法,文章的主要知识点来源为:
https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/leetcodesuan-fa-xiu-lian-dong-hua-yan-shi-xbian-2/
对于二叉树的遍历主要有三种形式,前序遍历、中序遍历、后序遍历;
所谓前序遍历,是指从根节点开始,对每一个节点,都采用先遍历该节点,再遍历其左子节点,最后遍历其右子节点的方式;
所谓中序遍历,是指从根节点开始,对每一个节点,都采用先遍历其左子节点,再遍历该节点,最后遍历其右子节点的方式;
所谓后序遍历,是指从根节点开始,对每一个节点,都采用先遍历其左子节点,再遍历其右子节点,最后遍历该节点的该当;

以一个二叉树图来说明一下。

对于上前所示的二叉树,其三种遍历方式的结果为:
前序遍历:1 2 4 5 3 6 7
中序遍历:4 2 5 1 6 3 7
后充遍历:4 5 2 6 7 3 1

下述中所用到的TreeNode数据结构如下所示:

class TreeNode:def __init__(self, value, left=None, right=None) -> None:self.m_value = valueself.m_left = leftself.m_right = rightdef setLeftChild(self, left):self.m_left = leftdef setRightChild(self, right):self.m_right = right

一、用递归法实现遍历

1.1 前序遍历

result = list()def preOrderRecur(root: TreeNode):# 若为空则返回if not root:return# 先记录当前节点的值result.append(root.m_value)# 再递归记录其左子树的各个值preOrderRecur(root.m_left)# 最后递归记录其右子树的各个值preOrderRecur(root.m_right)

1.2 中序遍历

result = list()
def inOrderRecur(root: TreeNode):if not root:return# 先递归遍历其左子树的各个值inOrderRecur(root.m_left)# 再记录当前值result.append(root.m_value)# 最后递归遍历其右子树的各个值inOrderRecur(root.m_right)

1.3 后序遍历

result = list()
def postOrderRecur(root: TreeNode):if not root:return# 先递归遍历其左子树的各个值postOrderRecur(root.m_left)# 再递归遍历其右子树的各个值postOrderRecur(root.m_right)# 最后记录当前节点值result.append(root.m_value)

二、用迭代法实现遍历

本质上是在模拟递归,因为在递归的过程中使用了系统栈,所以在迭代的解法中常用数据结构stack来模拟系统栈,在具体的python实现中,本文用list列表,且仅对最后一个元素作添加和删除操作来模拟栈,同时要注意的是栈是先进后出的数据结构。

2.1 前序遍历

基本的步骤是:
1 每访问到一个节点时,记录该节点的值;
2 之后按前序遍历的定义是要先记录左子树的值,再记录右子树的值,而栈是先进后出的结构特点,所以应该让其右子节点先入栈,再入左子节点。

result = list()
def preOrderIteration(root: TreeNode):if not root:returnnodeStack = list()# 当前节点先入栈nodeStack.append(root)while len(nodeStack):# 从栈中取出一个节点,表示的是当前遍历到该节点了node = nodeStack.pop()result.append(node.m_value)if node.m_right:nodeStack.append(node.m_right)if node.m_left:nodeStack.append(node.m_left)

2.2 中序遍历

基本步骤是:
1 创建一个Stack,以便于按 左 中 右的顺序输出节点。
2 尽可能的将这个节点的左子树压入Stack,此时栈顶的元素是最左侧的元素,其目的是找到一个最小单位的子树(也就是最左侧的一个节点),并且在寻找的过程中不断记录来源,这样才能逐步返回上层。在返回上层的时候,就意味着已经处理完毕左子树了。
3 当处理完最小单位的子树时,返回到上层处理了中间节点,记录下当前值。
4 判断如果有右节点,其也要对其进行一次中序遍历

result = list()
def inOrderIteration(root: TreeNode):if not root:returncurrentNode = rootnodeStack = list()while len(nodeStack) or currentNode:while currentNode:nodeStack.append(currentNode)currentNode = currentNode.m_leftnode = nodeStack.pop()result.append(node.m_value)if node.m_right:currentNode = node.m_right

2.3 后序遍历

2.3.1 后序解法一

1 前序遍历的过程是 中 左 右,而后序遍历的过程是 左 右 中。
2 修改前序遍历的实现过程为,中 右 左;即在压栈时,优先压入左子树,再压入右子树;
3 将步骤2得到的结果,倒序输出,就是后序遍历所期望的 左 右 中的结果。

result = list()
def postOrderIteration(root: TreeNode):if not root:returntmpResult = list()nodeStack = list()nodeStack.append(root)while len(nodeStack):node = nodeStack.pop()tmpResult.append(node.m_value)if node.m_left:nodeStack.append(node.m_left)if node.m_right:nodeStack.append(node.m_right)tmpResult.reverse()  result.extend(tmpResult)

2.3.2 后序解法二

基本步骤为:
1 用一个preNode,标记当前退出的节点是什么。
2 后序遍历的过程中,在遍历完左子树或右子树时,preNode都会回到其根结点。此时不应该再对该根结点的子节点做入栈操作,应该退回更上一层。

result = list()
def postOrderIteration2(root: TreeNode):if not root:returnpreNode = rootnodeStack = list()nodeStack.append(root)while len(nodeStack):# 注意,这里只是取栈顶元素,并没有出栈操作node = nodeStack[-1]if node.m_left and node.m_left != preNode and node.m_right != preNode:# 左子节点存在,且当前节点不是从其左子树或者右子树回退回来的根节点,# 此时可以入栈左子节点,以便于继续往左子树深入判断添加节点。nodeStack.append(node.m_left)elif node.m_right and node.m_right != preNode:# 右子节点存在,且当前节点不是从其右子树回退回来的,意味着,# 此时是遍历完了左子树后回退到根节点的,若此时有右子树的根节点,# 需要继续入栈该节点,以遍历右子树。nodeStack.append(node.m_right)else:# 走到这里,要么是已经访问到叶子节点了(即node.m_left和node.m_right都是None的结点,# 或者是遍历完左右子树后,回退到其根结点了,此时需要记录该节点的值,# 并更新preNode,记录当前处理的节点)preNode = nodeStack.pop()result.append(preNode.m_value)

三、测试验证

对代码作个测试验证。

def initTree():root = TreeNode(1)root_l = TreeNode(2)root_r = TreeNode(3)root_l_1 = TreeNode(4)root_l_2 = TreeNode(5)root_r_1 = TreeNode(6)root_r_2 = TreeNode(7)root_l.setLeftChild(root_l_1)root_l.setRightChild(root_l_2)root_r.setLeftChild(root_r_1)root_r.setRightChild(root_r_2)root.setLeftChild(root_l)root.setRightChild(root_r)result = list()
if __name__ == "__main__":tree = initTree()preOrderRecur(tree)print("preOrderRecur", result)result.clear()inOrderRecur(tree)print("inOrderRecur", result)result.clear()postOrderRecur(tree)print("postOrderRecur", result)result.clear()preOrderIteration(tree)print("preOrderIteration", result)result.clear()inOrderIteration(tree)print("inOrderIteration", result)result.clear()postOrderIteration(tree)print("postOrderIteration", result)result.clear()postOrderIteration2(tree)print("postOrderIteration2", result)

最终的输出结果为:
preOrderRecur [1, 2, 4, 5, 3, 6, 7]
inOrderRecur [4, 2, 5, 1, 6, 3, 7]
postOrderRecur [4, 5, 2, 6, 7, 3, 1]
preOrderIteration [1, 2, 4, 5, 3, 6, 7]
inOrderIteration [4, 2, 5, 1, 6, 3, 7]
postOrderIteration [4, 5, 2, 6, 7, 3, 1]
postOrderIteration2 [4, 5, 2, 6, 7, 3, 1]

二叉树的前序、中序、后序遍历相关推荐

  1. java中二叉树_Java工程师面试1000题224-递归非递归实现二叉树前、中、后序遍历...

    224.使用递归和非递归实现二叉树的前.中.后序遍历 使用递归来实现二叉树的前.中.后序遍历比较简单,直接给出代码,我们重点讨论非递归的实现. class Node { public int valu ...

  2. C++实现二叉树 前、中、后序遍历(递归与非递归)非递归实现过程最简洁版本

    本文并非我所写,是复制的该链接中的内容: 最近学习二叉树,想编程实现递归和非递归的实现方式: 递归的方式就不说了,因为大家的递归程序都一样:但是对于非递归的实现方式, 根据这几天的查阅资料已看到差不多 ...

  3. 【LeetCode | 二叉树前、中、后序遍历{迭代法}实现】

    1.前序遍历 // 解题思路:利用栈的原理实现以迭代方法来前序遍历(根左右)二叉树 class Solution { public:vector<int> preorderTraversa ...

  4. java数据结构学习笔记-二叉树前、中、后序遍历

    public class BinaryTreeDemo {public static void main(String args[]){Employee emp1= new Employee(1,&q ...

  5. 【LeetCode | 二叉树前、中、后序遍历{递归法}实现】

    1.前序遍历 #include <iostream> #include <vector> #include <queue> #include <algorit ...

  6. 二叉树前、中、后序线索化及遍历

    public class ThreadedBinaryTree {public static void main(String[] args){Heronodes node1=new Heronode ...

  7. 二叉树的前序中序后序遍历

    二叉树的前序中序后序遍历 二叉树的遍历 前序遍历 中序遍历 后序遍历 总结 二叉树的遍历 二叉树的遍历有前序遍历,中序遍历,后序遍历三种. 今天我把二叉树的遍历方法给大家总结一下,也算对我自己学习的一 ...

  8. 【二叉树Java】二叉树遍历前序中序后序遍历的非递归写法

    本文主要介绍二叉树前序中序后序遍历的非递归写法 在探讨如何写出二叉树的前序中序后序遍历代码之前,我们先来明确一个问题,前序中序后序遍历根据什么区分? 二叉树的前序中序后序遍历,是相较根节点说的.最先遍 ...

  9. 二叉树的前序中序后序遍历java代码实现

    1.前序遍历概述 前序遍历(VLR) 是二叉树遍历的一种,也叫做先根遍历.先序遍历.前序周游,可记做根左右.前序遍历首先访问根结点然后遍历左子树,最后遍历右子树. 若二叉树为空则结束返回,否则: (1 ...

  10. 二叉树遍历(递归实现前序/中序/后序遍历)

    1. 准备工作 我们先定义一棵普通的二叉树,如下图 2. 前序遍历 通过递归进行遍历: 如果二叉树为空,则操作返回: 如果非空,否则从根结点开始,然后遍历左子树,再遍历右子树. 前序遍历的结果是:AB ...

最新文章

  1. 小游戏来了 游戏小程序你想知道的这有
  2. apache +php + mysql_apache+php+mysql
  3. Android插件化开发基础之静态代理模式
  4. 简单好用的 Linux/Windows 面板
  5. 银行界加强计算机病毒管理,银行计算机管理系统维护现状与对策研究(7.12).doc...
  6. Swift中文教程(二十三) 高级运算符
  7. python中基本运算符_Python中的基本运算符及示例
  8. 教你一招用 Python Turtle 库画出“精美碎花小清新风格树”,速取代码! | 原力计划...
  9. 实践经验:应该如何使用Docker?
  10. 【MFC】黑马程序员MFC教程--基础篇
  11. Java:轻松一刻/程序员才懂的幽默
  12. 自定义返回上一步idea快捷键
  13. 微信内嵌H5网页 解决js倒计时失效
  14. Go语言处理Windows系统的图标ICO文件(中)
  15. 整理一下个人学习前端的网站
  16. HEVC/H.265编码HM码率控制
  17. 经济危机与宏观经济学
  18. 【Linux】Linux的挂载原理 |MOUNT|挂载NAS|自动挂载
  19. jquery、js去除浏览器(ff、ie)缓存问题
  20. M y s q l 篇

热门文章

  1. 映射网络驱动器共享网络硬盘
  2. YOLO算法学习总结
  3. windows10电脑连接热点网速贼慢,但USB网络共享和插网线却很快解决
  4. C++ 字符数组 :字符数组相互赋值
  5. [详解栈和队列]数据结构之栈与队列
  6. SR-TE Policy(思科)----Anycast-SID实验
  7. win10应用 UWP 使用MD5算法
  8. 项目质量要怎么保持? 如何借助系统软件进行管理
  9. 浅析阿里云一元公司注册的利与弊
  10. 特斯拉E/E整车电子电气创新架构分析