前言
书接上回,上边我们用伪代码的形式解释了树常见的通用遍历方式:前序、后续、广度优先,和二叉树专用的中序遍历。接下来,会按照上一节内容,为各位逐个展示各类遍历方法的核心代码,这些代码,可以添加在之前几节中写好的Tree类中(之前定义的一个树ADT)。
一、树的遍历
树T其中,应该包含两个方法:
1、T.positions():T的所有位置的迭代
2、iter(T):返回一个用树T存储元素的迭代器
我们先来实现一下 __ iter __()(该方法放在Tree中即可):
def __iter__(self):
for p in self.positions():# 通过positions返回所有位置的迭代,将其中每一个遍历,p代表每个位置。
yield p.element()# 调用该位置的element()方法得到该位置元素
要实现这里边提及的positions()方法,势必就涉及到了核心内容:遍历的方法。所以由此不难看出一个逆向思维,要想让树T可以实现通过iter()方法产生一个可以迭代的对象,就必须要实现其中的遍历树的方法positions(),再者,另外一个明显的结论:iter()调用T会返回一个树所有元素(element)组成的可迭代对象。那么我们开始实现各种方法的positions()吧。
1.1 先序遍历
首先考虑先序遍历,先序遍历的伪代码和基本思路已经在上一节当中为大家画图展示过了,可以参考上一节,这里不做赘述。我们先来完成上一节中的preorder(),preorder()返回树所有位置的迭代(注意不是positions(),等下会讲解为什么不是positions()),代码实现要大家记得上一节的先序遍历的伪代码哦。
def _subtree_preorder(self, p):# 非公开方法,实际是一个生成器
yield p# 先产生p
for c in self.children(p):#遍历该位置的子位置
for other in self._subtree_preorder(c):#生成子位置c的所有子树的位置
yield other
def preorder_fw(self):# 先序
if not self.is_empty():#如果树不为空
for p in self._subtree_preorder(self.root()):#先序遍历根
yield p
好了有些人为为什么不是positions(),因为:
def positions(self):
return self.preorder_fw()#返回整个迭代作为对象,而不是循环产生的某个结果。
明白了么?
1.2 后续遍历
后序遍历实际上就很简单了,因为可以由先序遍历转化而来:
def _subtree_postorder(self, p):# 非公开方法,实际是一个生成器
for c in self.children(p):#遍历该位置的子位置
for other in self._subtree_preorder(c):#生成子位置c的所有子树的位置
yield other
yield p # 最后产生位置p
def preorder_bk(self):# 后序
if not self.is_empty(): # 如果树不为空
for p in self._subtree_postorder(self.root()): # 先序遍历根
yield p
1.3广度优先遍历
这种方法是非递归的,借助队列来实现管理递归程序。我们用之前定义的LinkQueue()来实现:
def preorder_wp(self):#广度优先
if not self.is_empty():
que = LinkQueue()# 创建一个单向链表实现的队列
que.enqueue(self.root())# 根位置入队列
while not que.is_empty():# 空树不循环
p = que.dequeue()# 首元素出队列(先深度为n+1的位置,后n的位置)
yield p# 产生位置p
for c in self.children(p):
que.enqueue(c)# p的子位置入队列
1.4二叉树的中序遍历
至于中序遍历的逻辑,上一节。
def inorder(self):#中序
if not self.is_empty():
for p in self._subtree_inorder(self.root()):
yield p
def _subtree_inorder(self, p):#指定位置的中序遍历
if self.left(p) is not None:# 先指定位置的左子树
for other in self._subtree_inorder(self.left(p)):
yield other
yield p# 产生该位置
if self.right(p) is not None:#该位置的右子树
for other in self._subtree_inorder(self.right(p)):
yield other
def positions(self):
return self.inorder()