二叉树的前序、中序、后序遍历
文章目录
- 前言
- 一、用递归法实现遍历
- 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]
二叉树的前序、中序、后序遍历相关推荐
- java中二叉树_Java工程师面试1000题224-递归非递归实现二叉树前、中、后序遍历...
224.使用递归和非递归实现二叉树的前.中.后序遍历 使用递归来实现二叉树的前.中.后序遍历比较简单,直接给出代码,我们重点讨论非递归的实现. class Node { public int valu ...
- C++实现二叉树 前、中、后序遍历(递归与非递归)非递归实现过程最简洁版本
本文并非我所写,是复制的该链接中的内容: 最近学习二叉树,想编程实现递归和非递归的实现方式: 递归的方式就不说了,因为大家的递归程序都一样:但是对于非递归的实现方式, 根据这几天的查阅资料已看到差不多 ...
- 【LeetCode | 二叉树前、中、后序遍历{迭代法}实现】
1.前序遍历 // 解题思路:利用栈的原理实现以迭代方法来前序遍历(根左右)二叉树 class Solution { public:vector<int> preorderTraversa ...
- java数据结构学习笔记-二叉树前、中、后序遍历
public class BinaryTreeDemo {public static void main(String args[]){Employee emp1= new Employee(1,&q ...
- 【LeetCode | 二叉树前、中、后序遍历{递归法}实现】
1.前序遍历 #include <iostream> #include <vector> #include <queue> #include <algorit ...
- 二叉树前、中、后序线索化及遍历
public class ThreadedBinaryTree {public static void main(String[] args){Heronodes node1=new Heronode ...
- 二叉树的前序中序后序遍历
二叉树的前序中序后序遍历 二叉树的遍历 前序遍历 中序遍历 后序遍历 总结 二叉树的遍历 二叉树的遍历有前序遍历,中序遍历,后序遍历三种. 今天我把二叉树的遍历方法给大家总结一下,也算对我自己学习的一 ...
- 【二叉树Java】二叉树遍历前序中序后序遍历的非递归写法
本文主要介绍二叉树前序中序后序遍历的非递归写法 在探讨如何写出二叉树的前序中序后序遍历代码之前,我们先来明确一个问题,前序中序后序遍历根据什么区分? 二叉树的前序中序后序遍历,是相较根节点说的.最先遍 ...
- 二叉树的前序中序后序遍历java代码实现
1.前序遍历概述 前序遍历(VLR) 是二叉树遍历的一种,也叫做先根遍历.先序遍历.前序周游,可记做根左右.前序遍历首先访问根结点然后遍历左子树,最后遍历右子树. 若二叉树为空则结束返回,否则: (1 ...
- 二叉树遍历(递归实现前序/中序/后序遍历)
1. 准备工作 我们先定义一棵普通的二叉树,如下图 2. 前序遍历 通过递归进行遍历: 如果二叉树为空,则操作返回: 如果非空,否则从根结点开始,然后遍历左子树,再遍历右子树. 前序遍历的结果是:AB ...
最新文章
- 小游戏来了 游戏小程序你想知道的这有
- apache +php + mysql_apache+php+mysql
- Android插件化开发基础之静态代理模式
- 简单好用的 Linux/Windows 面板
- 银行界加强计算机病毒管理,银行计算机管理系统维护现状与对策研究(7.12).doc...
- Swift中文教程(二十三) 高级运算符
- python中基本运算符_Python中的基本运算符及示例
- 教你一招用 Python Turtle 库画出“精美碎花小清新风格树”,速取代码! | 原力计划...
- 实践经验:应该如何使用Docker?
- 【MFC】黑马程序员MFC教程--基础篇
- Java:轻松一刻/程序员才懂的幽默
- 自定义返回上一步idea快捷键
- 微信内嵌H5网页 解决js倒计时失效
- Go语言处理Windows系统的图标ICO文件(中)
- 整理一下个人学习前端的网站
- HEVC/H.265编码HM码率控制
- 经济危机与宏观经济学
- 【Linux】Linux的挂载原理 |MOUNT|挂载NAS|自动挂载
- jquery、js去除浏览器(ff、ie)缓存问题
- M y s q l 篇