Python二叉树的三种深度优先遍历

一、广度优先遍历和深度优先遍历

对二叉树进行遍历(traversal)是指依次对树中每个节点进行访问,在遍历的过程中实现需要的业务。

对树的遍历方式有广度优先遍历和深度优先遍历两种方式。广度优先一般用队列的方式,对树从上到下逐层遍历,每一层从左到右依次遍历。深度优先一般用递归的方式,遍历时会先尽可能深地遍历,直到叶节点。

在实现完全二叉树时,向完全二叉树中添加数据就是使用广度优先遍历,通过广度优先遍历找到第一个空位,将节点加到此位置。

参考:https://blog.csdn.net/weixin_43790276/article/details/104033490

对于一颗二叉树,深度优先遍历(Depth First Search)是沿着树的深度遍历树的节点,尽可能深地搜索树的分支。本文的重点是深度优先遍历的三种方式。

深度优先遍历有三种方式。这三种遍历方式分别叫做先序遍历(preorder)、中序遍历(inorder)和后序遍历(postorder),这三种方式常被用于访问树的节点,它们之间的不同在于访问每个节点的次序不同。

1. 先序遍历,也叫先根遍历。在先序遍历中,先访问树的根节点,然后递归使用先序遍历访问左子树,最后再递归使用先序遍历访问右子树。遍历顺序为:根节点 -> 左子树 -> 右子树。

2. 中序遍历,也叫中根遍历。在中序遍历中,先递归使用中序遍历访问左子树,然后访问树的根节点,最后再递归使用中序遍历访问右子树。遍历顺序为:左子树 -> 根节点 -> 右子树。

3. 后序遍历,也叫后根遍历。在后序遍历中,先递归使用后序遍历访问左子树,然后递归使用后序遍历访问右子树,最后再访问树的根节点。遍历顺序为:左子树 -> 右子树 -> 根节点。

在这三种遍历方式中,有两点需要注意,一是左右都是说子树,而不是子节点,所以遍历时不能理解成子节点。二是要递归地用相同的遍历方式处理子树,如先序遍历中,要遍历完整个左子树后,才开始遍历右子树,且不管左子树还是右子树,都是先序遍历。

不难发现,先、中、后都是针对访问根节点的先中后来说的,三种遍历方式的另一个名称就是因此而得。

二、实现一棵二叉树

要对二叉树进行遍历,需要先创建一棵二叉树,这里直接使用之前实现完全二叉树的代码,代码如下。

# coding=utf-8
class Node(object):def __init__(self, data):self.data = dataself.parent = Noneself.left_child = Noneself.right_child = Noneclass TreeQueue(object):def __init__(self):self.__members = list()def is_empty(self):return not len(self.__members)def enter(self, data):self.__members.insert(0, data)def outer(self):if self.is_empty():returnreturn self.__members.pop()class PerfectBinaryTree(object):def __init__(self):self.__root = Nonedef is_empty(self):return not self.__rootdef append(self, data):node = Node(data)if self.is_empty():self.__root = nodereturnqueue = TreeQueue()queue.enter(self.__root)while not queue.is_empty():cur = queue.outer()if cur.left_child is None:cur.left_child = nodenode.parent = curreturnqueue.enter(cur.left_child)if cur.right_child is None:cur.right_child = nodenode.parent = curreturnqueue.enter(cur.right_child)def show(self):if self.is_empty():print('空二叉树')returnqueue = TreeQueue()queue.enter(self.__root)while not queue.is_empty():cur = queue.outer()print(cur.data, end=' ')if cur.left_child is not None:queue.enter(cur.left_child)if cur.right_child is not None:queue.enter(cur.right_child)print()def get_root(self):return self.__root

代码里使用队列的方式实现了广度优先遍历,也叫层次遍历。

在二叉树深度优先遍历的三种方式中,都要使用递归的方式,而触发递归都是从根节点开始的,所以增加一个获取根节点的方法 get_root() ,供遍历时使用。

三、先序遍历

以上图为例,用先序遍历的方式对这棵树进行遍历,先访问根节点 A ,然后对左子树先序遍历,左子树的根节点是节点 B,再对 B 的左子树先序遍历,B 的左子树的根节点是节点 D,再对 D 的左子树先序遍历,D 的左子树的根节点是节点 H。H 没有子树了,D 的左子树遍历完了,对 D 的右子树先序遍历,D 的右子树的根节点是节点 I,D 的右子树也遍历完了。这时 B 的左子树也遍历完了,对 B 的右子树先序遍历,B 的右子树的根节点是节点 E,再对 E 的左子树先序遍历,E 的左子树的根节点是节点 J,E 的左子树遍历完了,E 没有右子树,所以 B 的右子树也遍历完了。看整棵树,根节点 A 的左子树遍历完了,再对 A 的右子树先序遍历,A 的右子树的根节点是节点 C ,再对 C 的左子树先序遍历,C 的左子树的根节点是节点 F,C 的左子树遍历完了,对 C 的右子树先序遍历,C 的右子树的根节点是节点 G ,到这里,整棵树就遍历完了。

先序遍历的结果是:A B D H I E J C F G 。

这个过程很长,我把全部步骤写了下来,这就是整个递归的过程,可以看到具体的每一个步骤,嫌烦可以跳过。

接下来用代码实现:

# 先根遍历(先序遍历)
def preorder_traversal(root):if root is None:returnprint(root.data, end=' ')preorder_traversal(root.left_child)preorder_traversal(root.right_child)

代码很简单,就是先处理(打印)根节点,然后递归处理左子树,最后再递归处理右子树。

四、中序遍历

有了先序遍历的逐步记录,中序遍历就不再赘述了。

对于上图中的二叉树,中序遍历的结果是:H D I B J E A F C G 。

代码如下:

# 中根遍历(中序遍历)
def inorder_traversal(root):if root is None:returninorder_traversal(root.left_child)print(root.data, end=' ')inorder_traversal(root.right_child)

代码也很简单,先递归处理(打印)左子树,然后处理根节点,最后再递归处理右子树。

五、后序遍历

同理,将根节点的处理放到最后,就是后序遍历了,这里也不再赘述过程。

还是上图中的二叉树,后序遍历的结果是:H I D J E B F G C A

代码如下:

# 后根遍历(后序遍历)
def postorder_traversal(root):if root is None:returnpostorder_traversal(root.left_child)postorder_traversal(root.right_child)print(root.data, end=' ')

代码还是很简单,先递归处理(打印)左子树,然后递归处理右子树,最后再处理根节点。

在这三种遍历方式中,理解了递归的思想,这三个函数就非常好理解了。

下面将层次遍历和三种深度优先遍历的运行结果放到一起进行比较。

if __name__ == '__main__':tree = PerfectBinaryTree()for alpha in ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']:tree.append(alpha)print('层次遍历: ', end='')tree.show()print('先序遍历: ', end='')preorder_traversal(tree.get_root())print()print('中序遍历: ', end='')inorder_traversal(tree.get_root())print()print('后序遍历: ', end='')postorder_traversal(tree.get_root())print()

运行结果:

层次遍历: A B C D E F G H I J
先序遍历: A B D H I E J C F G
中序遍历: H D I B J E A F C G
后序遍历: H I D J E B F G C A 

Python二叉树的三种深度优先遍历相关推荐

  1. Python实现二叉树的三种深度遍历方法!

    python代码实现了二叉树,这次将会实现二叉树的几种遍历方法,来更好的解析二叉树的结构特点.分别是一种广度遍历,和三种深度遍历方法:先序遍历,中序遍历,后序遍历.下面是代码实现: 1.先序遍历 遍历 ...

  2. C语言 数据结构 二叉树实现、二叉树的三种递归遍历

    二叉树 在计算机科学中,二叉树(英语:Binary tree)是每个节点最多只有两个分支(即不存在分支度大于2的节点)的树结构.通常分支被称作"左子树"或"右子树&quo ...

  3. Python培训讲解二叉树的三种深度

    python代码实现了二叉树,这次将会实现二叉树的几种遍历方法,来更好的解析二叉树的结构特点.分别是一种广度遍历,和三种深度遍历方法:先序遍历,中序遍历,后序遍历.下面是代码实现: 1.先序遍历 遍历 ...

  4. Python教程讲解二叉树的三种深度

    python代码实现了二叉树,这次将会实现二叉树的几种遍历方法,来更好的解析二叉树的结构特点.分别是一种广度遍历,和三种深度遍历方法:先序遍历,中序遍历,后序遍历.下面是代码实现: 1.先序遍历 遍历 ...

  5. C语言基本数据结构之二(二叉树的三种遍历,节点数以及深度算法)

    关于二叉树的定义,网上有比较好的介绍,在这里就简单介绍二叉树的一些性质 二叉树的基本性质 1)二叉树的第i层上至多有 2^(i-1)(i ≥1)个结点: 2)深度为 h 的二叉树中至多含有 2^h – ...

  6. c语言中二叉树中总结点,C语言二叉树的三种遍历方式的实现及原理

    二叉树遍历分为三种:前序.中序.后序,其中序遍历最为重要.为啥叫这个名字?是根据根节点的顺序命名的. 比如上图正常的一个满节点,A:根节点.B:左节点.C:右节点,前序顺序是ABC(根节点排最先,然后 ...

  7. 二叉树的三种遍历(递归与非递归) + 层次遍历

    <转载于  >>> > 二叉树是一种非常重要的数据结构,很多其他数据机构都是基于二叉树的基础演变过来的.二叉树有前.中.后三种遍历方式,因为树的本身就是用递归定义的,因此 ...

  8. 二叉树----数据结构:二叉树的三种遍历及习题

    二叉树----数据结构:二叉树的三种遍历,利用递归算法. 关于二叉树的遍历,应用非常广泛,不单单是访问打印结点,还可以进行一系列的操作,如赋值.删除.查找.求二叉树的深度等等. 有递归和非递归两种算法 ...

  9. 实现二叉树的三种非递归遍历算法

    [问题描述] 编写程序,实现二叉树的三种非递归遍历算法:先序非递归,中序非递归,后序非递归. [输入形式] 输入建树序列. [输出形式] 输出三种遍历序列. [样例输入] A B C # # # # ...

最新文章

  1. 如果特斯拉制造相机的梦想像激光雷达一样真正实现,它可能会帮助到更多同行...
  2. AI已经融入生活,不懂AI的人已经out了,五分钟了解AI人工智能!
  3. 想直接在 IDEA 里面快乐的刷刷LeetCode算法题吗?
  4. 【Jenkins持续集成】docker部署+配置+操作Jenkins
  5. Kafka 是如何保证数据可靠性和一致性
  6. java快捷键查看目录,java取得快捷方式指向的路径
  7. Java零基础入门 : (2) 代码编辑器IDEA安装与配置
  8. Python学习笔记(四十)— 内置模块(9)HTMLParser
  9. js生成随机密码,密码位数自定
  10. ubuntu中安装flash播放器
  11. 怎么修改打印机服务器权限,Win7怎么设置网络打印机管理权限?
  12. 【巴迪亲子英语启蒙课堂】会日常单词,会简单对话,自主对话不行怎么办?是否要加强英文对话?
  13. Android Studio上Kotlin的入门,移动应用系统开发
  14. android+高德地图教程,Android高德地图开发(三)地图简单操作
  15. 我的专业偶像作文计算机,我的崇拜的偶像作文(通用5篇)
  16. Automa 和看小说脚本
  17. 利用TabNet进行股票长线预测
  18. ESP8266/ESP32 基础篇: 时间同步 SNTP 介绍和使用
  19. 微信建群怎么建?不止一种方法,快试试这个!
  20. java动物代码_Java基于接口实现模拟动物声音代码实例

热门文章

  1. 2018-2019-1 20165325 《信息安全系统设计基础》第七周学习总结
  2. 不停止nginx服务的情况下替换nginx执行文件
  3. NFS与NAS谁更适合VMware
  4. 为什么拙劣的软件也会成功?
  5. 如何在Visual Studio中开发自己的代码生成器插件
  6. Custom Looks using Qt Style Sheets
  7. Jser 设计模式系列之面向对象 - 接口封装与继承
  8. pku 1511 Invitation Cards
  9. SQL2005 学记笔记(9)
  10. 迁移 Docker 到其它磁盘目录