引言
二叉树是一种非常常见且重要的数据结构,它广泛应用于计算机科学和算法的设计中。其中,二叉树所用的数据结构关系比较简单,适合各类算法的实现。这篇文章将会介绍基于Python的BinaryTree实现,它为我们深入了解二叉树的工作方式和如何应用算法提供了一个很好的起点。
二叉树数据结构
二叉树是由节点组成的树状数据结构,每个节点有一个值、一个左节点、和一个右节点。左节点和右节点可以是空值。如果节点的左、右节点都不为空,那么分别称这个节点为该节点左孩子和右孩子。如果一个节点没有子节点,那么称这个节点为叶节点。
class Node:
def __init__(self, val: int):
self.value = val
self.left = None
self.right = None
上面的代码创建了一个简单的节点类。它有一个值、一个左节点和右节点。left、right 可以是一个Node类型或者None。
二叉树的遍历
遍历是指按照一定次序,依次对所有的节点进行访问。在二叉树中,最常见的遍历方式为:前序遍历、中序遍历、后序遍历和层序遍历。
前序遍历
前序遍历的顺序是:根节点、左子树、右子树。以下是前序遍历的代码:
def pre_order_traversal(node: Node):
if node is None:
return
print(node.value, end=' ')
pre_order_traversal(node.left)
pre_order_traversal(node.right)
中序遍历
中序遍历的顺序是:左子树、根节点、右子树。以下是中序遍历的代码:
def in_order_traversal(node: Node):
if node is None:
return
in_order_traversal(node.left)
print(node.value, end=' ')
in_order_traversal(node.right)
后序遍历
后序遍历的顺序是:左子树、右子树、根节点。以下是后序遍历的代码:
def post_order_traversal(node: Node):
if node is None:
return
post_order_traversal(node.left)
post_order_traversal(node.right)
print(node.value, end=' ')
层序遍历
层序遍历即按照层次依次访问,使用队列实现。从根节点开始,先将根节点压入队列,每次从队列中取出一个节点,若其左子节点不为空,则将左子节点压入队列,同样,如果其右子节点不为空,则将右子节点压入队列。直到队列为空为止。
def level_order_traversal(root: Node):
if not root: return []
res, queue = [], [root]
while queue:
level_res = []
size = len(queue)
for _ in range(size):
node = queue.pop(0)
level_res.append(node.value)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
res.append(level_res)
return res
二叉树的查找、插入、删除
查找操作
因为二叉树的数据结构可以保持其子树中的所有左子树的值都小于父节点的值,子树中所有右子树的值都大于父节点的值。因此,查找一个值可以使用下面代码:
def search_bst(root: Node, val: int):
while root and root.value != val:
if val < root.value:
root = root.left
else:
root = root.right
return root
插入操作
插入节点操作,加入一个节点到二叉树中。可以使用下面代码实现:
def insert_node(root: Node, val: int):
if not root: return Node(val)
if root.value < val:
root.right = insert_node(root.right, val)
elif root.value > val:
root.left = insert_node(root.left, val)
return root
删除操作
二叉树中的节点是可以被删除的,删除一个节点需要知道一个尽量好的节点来取代被删除的节点。在二叉树中,常见的取代方式是:将右子树中最小的节点或者左子树中最大的节点取代要删除的节点。这里我们仅实现将右子树中最小的节点取代的情况,可以使用如下代码:
def remove_node(root: Node, val: int):
if not root: return None
if root.value == val:
# 左右孩子均为空
if not root.left and not root.right:
return None
# 左右孩子均非空
elif root.left and root.right:
min_node = root.right
while min_node.left:
min_node = min_node.left
root.value = min_node.value
root.right = remove_node(root.right, min_node.value)
# 左孩子为空
elif not root.left:
return root.right
# 右孩子为空
elif not root.right:
return root.left
elif root.value < val:
root.right = remove_node(root.right, val)
else:
root.left = remove_node(root.left, val)
return root
应用示例:判断二叉树是否为BST
上面我们已经介绍了二叉树的遍历、查找、插入和删除操作。这里我们以判断一个二叉树是否为BST为例子,并展示如何使用二叉树进行算法设计。 该算法需要判断二叉树是否符合BST的定义,即左子树的所有节点应该的小于其父节点,右子树的所有节点应该大于其父节点。可以递归进行判断:
def is_valid_bst(root: Node) -> bool:
def check(root, left, right):
if not root:
return True
if left and root.value <= left.value:
return False
if right and root.value >= right.value:
return False
return check(root.left, left, root) and check(root.right, root, right)
return check(root, None, None)
结论
本文介绍了Python语言中的二叉树数据结构。通过对这些算法的详细解释和Python实现,我们希望能够帮助读者更好地理解和应用该数据结构。这些算法是程序员必备的基础算法,不仅在面试中经常被提及,而且在实际工作中也经常被使用。