树的遍历(Tree Traversals)
对一个数据集中的所有数据项进行访问的操作称为“遍历Traversal”。
线性数据结构中,对其所有数据项的访问比较简单直接,按照顺序依次进行即可。树的非线性特点,使得遍历操作较为复杂。我们按照对节点访问次序的不同来区分3种遍历:
-
前序遍历(preorder):先访问根节点,再递归地前序访问左子树、最后前序访问右子树;
上图二叉树的前序遍历为:
A->B->D->G->H->I->C->E->J->F
-
中序遍历(inorder):先递归地中序访问左子树,再访问根节点,最后中序访问右子树;
上图二叉树的中序遍历为:
G->D->I->H->B->A->E->J->C->F
-
后序遍历(postorder):先递归地后序访问左子树,再后序访问右子树,最后访问根节点。
上图二叉树的后序遍历为:
G->I->H->D->B->J->E->F->C->A
python代码实现
树遍历的代码非常简洁,不同的遍历顺序仅需要调整递归顺序即可。
def preorder(tree):
"""前序遍历"""
if tree:
print(tree.get_root_val())
preorder(tree.get_left_child())
preorder(tree.get_right_child())
def inorder(tree):
"""中序遍历"""
if tree is not None:
inorder(tree.get_left_child())
print(tree.get_root_val())
inorder(tree.get_right_child())
def postorder(tree):
"""后序遍历"""
if tree is not None:
postorder(tree.get_left_child())
postorder(tree.get_right_child())
print(tree.get_root_val())
也可以在BinaryTree类中实现前序遍历方法。
class BinaryTree:
...
def preorder(self):
print(self.key)
if self.left_child:
self.left_child.preorder()
if self.right_child:
self.right_child.preorder()
后序遍历:表达式求值
上一篇文章中的的表达式解析树求值,实际上也是一个后序遍历的过程。所以,我们可以采用后序遍历法重写表达式求值代码:
def postordereval(tree):
opers = {
"+": operator.add,
"-": operator.sub,
"*": operator.mul,
"/": operator.truediv,
}
res1 = None
res2 = None
if tree: #基本结束条件
res1 = postordereval(tree.get_left_child())
res2 = postordereval(tree.get_right_child())
if res1 and res2:
#递归调用
return opers[tree.get_root_val()](res1, res2)
else:
return tree.get_root_val() #基本结束条件
中序遍历:生成全括号中缀表达式
采用中序遍历递归算法,可以实现生成全括号中缀表达式。
下列代码中对每个数字也加了括号,请自行修改代码去除。
def printexp(tree):
# 初始化表达式
s_val = ""
if tree:
s_val = "(" + printexp(tree.get_left_child())
s_val += str(printexp(tree.get_root_val()))
s_val += printexp(tree.get_right_child()) + ")"
return s_val