二叉树
二叉树(binary tree)是一种非线性数据结构,代表“祖先”与“后代”之间的派生关系,体现了“一分为二”的分治逻辑。与链表类似,二叉树的基本单元是节点,每个节点包含值、左子节点引用和右子节点引用。
1二叉树基本结构
树节点
# 二叉树的基本结构
class TreeNode:
def __init__(self,val:int):
# 节点值
self.val: int = val
# 左叶子结点
self.left: TreeNode|None=None
# 右叶子节点
self.right:TreeNode|None=None
初始化二叉树
# 二叉树初始化
t1 = TreeNode(1)
t2 = TreeNode(2)
t3 = TreeNode(3)
t4 = TreeNode(4)
t5 = TreeNode(5)
t1.left = t2
t1.right = t3
t2.left = t4
t2.right = t5
2、插入与删除节点
# 插入节点
p = TreeNode(99)
# 我们在t1.left节点插入P节点
# 首先P节点指向原来的叶子结点
p.left = t1.left
# t1.left指向p
t1.left = p
# 删除节点,直接指向删除节点的叶子结点
t1.left = p.left
3、广度优先遍历
# 首先定义一个队列,存储需要便利的节点,队列先进先出特点可以保证层序遍历的顺序
# 然后根据通过队列元素出队记录访问节点值,并根据左子树与右子树进一步确定后续的广度优先遍历顺序
def level_order(root: TreeNode):
"""层序遍历"""
# 初始化队列
queue: deque[TreeNode] = deque()
# 加入根节点
queue.append(root)
# 初始化一个列表,用于保存遍历序列
res = []
# 队列不为空则继续执行
while queue:
# 循环1、访问根节点
# 循环2、访问队列中第一层左子树
# 循环3、访问队列中第一层右子树
# 循环4、访问队列中第二层左子树
node: TreeNode = queue.popleft() # 队列出队
# 循环1、记录访问根节点元素
# 循环2、记录左子树节点值
res.append(node.val) # 保存节点值
# 循环1、判定第一层左子树
# 循环2、判定第二层左子树
if node.left is not None:
# 1、若第一层左子树不为空
# 2、若第二层左子树不为空
queue.append(node.left) # 左子节点入队
# 判断右子树
if node.right is not None:
# 若右子树不为空
queue.append(node.right) # 右子节点入队
return res
data = level_order(t1)
print(data)
2、深度遍历
利用递归,分别深度递归叶子结点,然后回溯记录节点值
根据记录节点值的阶段,可以分为前序、中序、后序
res = []
# 深度优先搜索
# 前序遍历
def pre_dbfs(tree):
# 存储数组的元素
# 终止条件:节点为None
if tree== None:
return
# 首先访问左叶子结点
res.append(tree.val)
# 前序遍历
# 首先深度遍历左子节点
pre_dbfs(tree.left)
# 遇见None节点在深度遍历右子节点
pre_dbfs(tree.right)
# 后序遍历
def in_dbfs(tree):
# 终止条件:节点为None
if tree== None:
return
# 前序遍历
# 首先深度遍历左子节点
end_dbfs(tree.left)
# 第一轮回溯记录根节点
res.append(tree.val)
# 深度遍历右子节点,回溯,记录右子节点
end_dbfs(tree.right)
# 完成第一个叶子树的回溯
def end_dbfs(tree):
# 终止条件:节点为None
if tree== None:
return
# 前序遍历
# 首先深度遍历左子节点
end_dbfs(tree.left)
# 第一轮回溯记录根节点
res.append(tree.val)
# 深度遍历右子节点,回溯,记录右子节点
end_dbfs(tree.right)
# 完成第一个叶子树的回溯
test = in_dbfs(t1)