返回
二叉树遍历:以“黑白标记法”为切入点,深入理解前中后序
后端
2024-01-04 22:30:56
前言
作为一名技术爱好者,您是否遇到过这样的困扰:需要遍历二叉树,但却被前中后序遍历的递归法和迭代法搞得晕头转向?别担心,本文将为您拨开迷雾,带您深入理解这三种遍历方法,并介绍一种简单易记的迭代法模版——“黑白标记法”。
理解二叉树遍历
二叉树遍历是计算机科学和编程中的一个基本算法,它用于访问二叉树中的所有节点。二叉树遍历有三种基本方式:前序遍历、中序遍历和后序遍历。
- 前序遍历: 根节点、左子树、右子树
- 中序遍历: 左子树、根节点、右子树
- 后序遍历: 左子树、右子树、根节点
递归法:简单易懂,但有局限性
递归法是实现二叉树遍历最直接的方法。它的原理很简单:
- 访问根节点。
- 递归地遍历左子树。
- 递归地遍历右子树。
def preorder_traversal(root):
if root is None:
return
# 访问根节点
print(root.data)
# 递归地遍历左子树
preorder_traversal(root.left)
# 递归地遍历右子树
preorder_traversal(root.right)
def inorder_traversal(root):
if root is None:
return
# 递归地遍历左子树
inorder_traversal(root.left)
# 访问根节点
print(root.data)
# 递归地遍历右子树
inorder_traversal(root.right)
def postorder_traversal(root):
if root is None:
return
# 递归地遍历左子树
postorder_traversal(root.left)
# 递归地遍历右子树
postorder_traversal(root.right)
# 访问根节点
print(root.data)
递归法简单易懂,但也有局限性。当二叉树非常庞大的时候,递归法会消耗大量的栈空间,甚至导致栈溢出。
迭代法:空间复杂度更低,效率更高
迭代法是实现二叉树遍历的另一种方法。它的原理也很简单:
- 使用栈来存储要访问的节点。
- 将根节点压入栈中。
- 循环执行以下步骤,直到栈为空:
- 弹出栈顶元素,并访问它。
- 如果它有右子树,则将右子树压入栈中。
- 如果它有左子树,则将左子树压入栈中。
def preorder_traversal_iterative(root):
stack = [root]
while stack:
# 弹出栈顶元素,并访问它
node = stack.pop()
print(node.data)
# 如果它有右子树,则将右子树压入栈中
if node.right:
stack.append(node.right)
# 如果它有左子树,则将左子树压入栈中
if node.left:
stack.append(node.left)
def inorder_traversal_iterative(root):
stack = []
node = root
while stack or node:
# 如果当前节点不为空,则将其压入栈中并继续访问其左子树
if node:
stack.append(node)
node = node.left
# 如果当前节点为空,则弹出栈顶元素并访问它,然后访问其右子树
else:
node = stack.pop()
print(node.data)
node = node.right
def postorder_traversal_iterative(root):
stack = []
last_visited = None
while stack or root:
# 如果当前节点不为空,则将其压入栈中并继续访问其左子树
if root:
stack.append(root)
root = root.left
# 如果当前节点为空,则说明左子树已经访问完毕,此时访问右子树
else:
root = stack[-1]
# 如果右子树已经访问完毕,则弹出栈顶元素并访问它
if not root.right or last_visited == root.right:
root = stack.pop()
print(root.data)
last_visited = root
root = None
# 否则,访问右子树
else:
root = root.right
迭代法的时间复杂度与递归法相同,但空间复杂度更低。因此,当二叉树非常庞大的时候,迭代法是更好的选择。
黑白标记法:简单易记的迭代法模版
“黑白标记法”是一种实现二叉树遍历的迭代法模版。它的原理很简单:
- 将所有节点标记为“白色”。
- 从根节点开始,访问它并将其标记为“黑色”。
- 循环执行以下步骤,直到所有节点都被标记为“黑色”:
- 找到一个标记为“白色”的节点,将其标记为“灰色”。
- 访问该节点。
- 将其左子树和右子树标记为“白色”。
def tree_traversal_黑白标记法(root, traversal_type):
# 将所有节点标记为“白色”
for node in tree.nodes:
node.color = "white"
# 从根节点开始,访问它并将其标记为“黑色”
root.color = "black"
# 循环执行以下步骤,直到所有节点都被标记为“黑色”
while True:
# 找到一个标记为“白色”的节点,将其标记为“灰色”
node = find_white_node(tree)
if node is None:
break
node.color = "gray"
# 访问该节点
if traversal_type == "preorder":
print(node.data)
elif traversal_type == "inorder":
# 如果该节点的左子树已经访问完毕,则访问该节点
if node.left.color == "black":
print(node.data)
# 否则,访问该节点的左子树
else:
node = node.left
elif traversal_type == "postorder":
# 如果该节点的左右子树都已经访问完毕,则访问该节点
if node.left.color == "black" and node.right.color == "black":
print(node.data)
# 否则,访问该节点的左子树或右子树
else:
if node.left.color == "white":
node = node.left
else:
node = node.right
# 将其左子树和右子树标记为“白色”
node.left.color = "white"
node.right.color = "white"
“黑白标记法”简单易记,并且可以用于实现任何类型的二叉树遍历。
结语
本文介绍了二叉树的前中后序遍历算法,并重点介绍了一种简单易记的迭代法模版——“黑白标记法”。希望这些知识能够帮助您更好地理解二叉树遍历算法,并在实际开发中熟练运用它们。