1.二叉树的定义
二叉树是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成,如图1所示。
2.二叉树的遍历
当我们在写代码使用树这种结构时,需要对树进行一些操作。其中,最基础的操作就是遍历。树的遍历一般分为,前序遍历、中序遍历和层次遍历。我们通常把树分为三部分,即左子树、根节点(中间节点)和右节点。根据访问顺序的不同定义除了不同的遍历。以图1为例展示不同遍历的结果。
前序遍历的顺序:根节点->左子树->右节点,1 2 4 5 3。
中序遍历的顺序:左子树->根节点->右节点,4 2 5 1 3。
后序遍历的顺序:左子树->右节点->根节点,4 5 2 3 1。
3.遍历的代码实现
一般来说,遍历的实现存在递归法和迭代法两种。
3.1递归法
优点:代码少,易理解。
缺点:但是容易造成栈的溢出。此外因为要不断的调用函数,所以其需要的运行空间较大。
代码如下:
# Definition for a binary tree node.
from typing import Optional
# 节点类
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val # 节点的值
self.left = left # 节点的左孩子
self.right = right # 节点的右孩子
# 前序遍历:中、左、右
def preordertraversal(root: Optional[TreeNode]) -> list[int]:
def traversal(node):
if node == None: # 递归出口
return
result.append(node.val) # 中
traversal(node.left) # 左
traversal(node.right) # 右
result = []
traversal(root) # 调用递归函数
return result
def inordertraversal(root: Optional[TreeNode]) -> list[int]:
def traversal(node):
if not node: # 递归出口
return
traversal(node.left) # 左
result.append(node.val) # 中
traversal(node.right) # 右
result = []
traversal(root) # 调用递归函数
return result
def postordertraversal(root: Optional[TreeNode]) -> list[int]:
def traversal(node):
if not node:
return
traversal(node.left) # 左
traversal(node.right) # 右
result.append(node.val) # 中
result = []
traversal(root) # 调用递归函数
return result
if __name__ == "__main__":
# 这里我手动创建一棵树
tree_list = [1, 2, 3, 4, 5]
root = TreeNode(tree_list[0]) # 节点1
node_1 = TreeNode(tree_list[1]) # 节点2
node_2 = TreeNode(tree_list[2]) # 节点3
node_3 = TreeNode(tree_list[3]) # 节点4
node_4 = TreeNode(tree_list[4]) # 节点5
root.left, root.right = node_1, node_2
node_1.left, node_1.right = node_3, node_4
# 前序遍历
pre_result = preordertraversal(root)
print("前序遍历结果:", pre_result)
# 中序遍历
in_result = inordertraversal(root)
print("中序遍历结果:", in_result)
# 前序遍历
post_result = postordertraversal(root)
print("后序遍历结果:", post_result)
3.2统一迭代法
优点:需要的运行空间较少,效率更高。
缺点:代码多,不易理解。
统一迭代法:使用统一的思路迭代遍历二叉树迭代法。迭代法最需要注意的地方就是什么时候出栈元素。我们在每个需要出栈并添加到最终的result中的节点后加入一个“None”作为标志,以此来判断出栈的时机,最终实现用统一的思想来书写遍历代码。
代码如下:
from typing import Optional
# 节点类
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val # 节点的值
self.left = left # 节点的左孩子
self.right = right # 节点的右孩子
# 前序遍历:中、左、右
def preordertraversal(root: Optional[TreeNode]) -> list[int]:
if not root: # 当根节点为空时,直接返回
return []
stack = [root] # 栈结构:保存遍历过程的节点
result = [] # 最终输出的遍历顺序
while stack: # 当栈不为空时,继续遍历
node = stack.pop() # 出栈一个节点
if node: # 该节点不为空时,加入其孩子节点。由于栈是先进后出,所以要先将右节点入栈,然后是左节点,最后是中间节点
if node.right:
stack.append(node.right) # 右边节点入栈,
if node.left:
stack.append(node.left) # 左边节点入栈
stack.append(node) # 中间节点入栈
stack.append(None) # 标志:遇见None就说明出栈中间节点了
else: # 该节点为空,再出栈一个元素,并将其加入到最终的result中
node = stack.pop()
result.append(node.val)
return result
# 中序遍历:左、中、右
def inordertraversal(root: Optional[TreeNode]) -> list[int]:
if not root: # 当根节点为空时,直接返回
return []
stack = [root] # 栈结构:保存遍历过程的节点
result = [] # 最终输出的遍历顺序
while stack: # 当栈不为空时,继续遍历
node = stack.pop() # 出栈一个节点
if node: # 该节点不为空时,加入其孩子节点。此处是中序遍历,所以要换一下加入栈的顺序。所以要先将右节点入栈,然后是中间节点,最后是左节点。
if node.right:
stack.append(node.right) # 右节点入栈
stack.append(node) # 中间节点入栈
stack.append(None) # 标志:遇见None就说明出栈中间节点了
if node.left:
stack.append(node.left) # 左结点入栈
else: # 该节点为空,再出栈一个元素,并将其加入到最终的result中
node = stack.pop()
result.append(node.val)
return result
# 后序遍历:左、中、右
def postordertraversal(root: Optional[TreeNode]) -> list[int]:
if not root: # 当根节点为空时,直接返回
return []
stack = [root] # 栈结构:保存遍历过程的节点
result = [] # 最终输出的遍历顺序
while stack: # 当栈不为空时,继续遍历
node = stack.pop() # 出栈一个节点
if node: # 该节点不为空时,加入其孩子节点。此处是后序遍历,所以要换一下加入栈的顺序。所以要先将中间节点入栈,然后是右节点,最后是左节点。
if node.right:
stack.append(node.right) # 右节点入栈
stack.append(node) # 中间节点入栈
stack.append(None) # 标志:遇见None就说明出栈中间节点了
if node.left:
stack.append(node.left) # 左结点入栈
else: # 该节点为空,再出栈一个元素,并将其加入到最终的result中
node = stack.pop()
result.append(node.val)
return result
if __name__ == "__main__":
# 这里我手动创建一棵树
tree_list = [1, 2, 3, 4, 5]
root = TreeNode(tree_list[0]) # 节点1
node_1 = TreeNode(tree_list[1]) # 节点2
node_2 = TreeNode(tree_list[2]) # 节点3
node_3 = TreeNode(tree_list[3]) # 节点4
node_4 = TreeNode(tree_list[4]) # 节点5
root.left, root.right = node_1, node_2
node_1.left, node_1.right = node_3, node_4
# 前序遍历
pre_result = preordertraversal(root)
print("前序遍历结果:", pre_result)
# 中序遍历
in_result = inordertraversal(root)
print("中序遍历结果:", in_result)
# 前序遍历
post_result = postordertraversal(root)
print("后序遍历结果:", post_result)