一、二叉树的种类
两种主要的形式:满二叉树和完全二叉树
1. 满二叉树Full Binary Tree
满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。

结构:深度为k,有2^k-1个节点的二叉树
2. 完全二叉树 Complete Binary Tree
完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层(h从1开始),则该层包含 1~ 2^(h-1) 个节点。

*** 堆heap就是一棵完全二叉树,同时保证父子节点的顺序关系
堆属性:在最大堆中,任何一个父节点的值都大于或等于它的子节点;在最小堆中,则相反,父节点的值小于或等于其子节点。
3. 二叉搜索树 Binary Search Tree BST
二叉搜索树是一个有序树,满足:
1. 左子树的值小于根节点的值:对于一个节点 N,其左子树上所有节点的值都小于 N 的值。
2. 右子树的值大于根节点的值:对于一个节点 N,其右子树上所有节点的值都大于 N 的值。
3. 每个子树也是二叉搜索树:这意味着二叉搜索树的性质对每个节点及其子树都成立。

4. 平衡二叉搜索树 Balanced Binary Search Tree, BBST
常见的平衡二叉搜索树类型:
1. AVL 树(Adelson-Velsky and Landis Tree):
• 每个节点的左右子树高度差最多为 1。
• 每次插入或删除节点后,通过旋转操作(左旋、右旋、双旋)来重新平衡树。
• 适合在插入和删除操作较少的情况下使用,因为频繁的旋转操作会带来较大的开销。
2. 红黑树(Red-Black Tree):
• 是一种近似平衡的二叉搜索树,每个节点附加一个颜色属性(红色或黑色)。
• 保持了比 AVL 树更松的平衡条件,插入和删除操作的效率更高,因此应用广泛。
• 常用于 Java 的 TreeMap、TreeSet 以及 Python 的 dict 等实现中。
3. B 树和 B+ 树:
• 不是严格的二叉树,而是多路平衡搜索树,主要用于数据库和文件系统。
• 每个节点可以有多个子节点,使得树的高度更低,从而更适合磁盘存储结构。
二、二叉树的存储方式
主要有两种:链式存储和顺序存储
1. 链式存储:通常使用指针或引用来实现,因此不需要完整的连续空间。
• 优点:
内存利用率高:只为实际存在的节点分配内存空间,适合表示结构不完整的二叉树(如普通二叉树和二叉搜索树)。
适用于动态二叉树:可以灵活地进行插入和删除操作。
• 缺点:
节点访问不直接:要访问特定节点需要从根节点逐步遍历
2. 顺序存储:使用数组将二叉树的节点按层次顺序存储在连续的存储空间中,适合完全二叉树(或接近完全的二叉树),因为完全二叉树的节点位置关系在数组中可以通过简单的公式确定。
• 存储规则:
• 根节点存储在数组的第一个位置(索引 0 或 1,根据实现不同)。
• 若节点的索引为 i,则:
• 左孩子节点的索引为 2*i + 1(或 2*i,基于索引起始位置)。
• 右孩子节点的索引为 2*i + 2(或 2*i + 1)。
• 父节点的索引为 (i - 1) // 2。
• 优点:
• 节点访问高效:数组存储,访问节点速度快,适合用于完全二叉树结构。
• 缺点:
• 空间浪费:不适合非完全二叉树或稀疏二叉树,因为这会导致大量数组空间浪费。
• 扩展性差:在动态插入和删除节点时不灵活,通常用于静态结构的二叉树。
三、二叉树的遍历方式
二叉树的遍历方式主要有四种:前序遍历、中序遍历、后序遍历和层序遍历。其中前序、中序和后序遍历是深度优先遍历(DFS),层序遍历是广度优先遍历(BFS)。
深度优先遍历:前中后,指的就是中间节点的遍历顺序
- 前序遍历(递归法,迭代法)
- 中序遍历(递归法,迭代法)
- 后序遍历(递归法,迭代法)
广度优先遍历
- 层次遍历(迭代法)
四、二叉树的定义
class TreeNode:
def __init__(self, val, left = None, right = None):
self.val = val
self.left = left
self.right = right
五、二叉树的递归遍历
1. 前序
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans = []
def dfs(node):
if node is None:
return
ans.append(node.val)
dfs(node.left)
dfs(node.right)
dfs(root)
return ans
2. 中序
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans = []
def dfs(node):
if node is None:
return
dfs(node.left)
ans.append(node.val)
dfs(node.right)
dfs(root)
return ans
3. 后序
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans= []
def dfs(node):
if node is None:
return
dfs(node.left)
dfs(node.right)
ans.append(node.val)
dfs(root)
return ans
六、二叉树的迭代遍历
1. 先序
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
stack = [root]
result = []
while stack:
node = stack.pop()
result.append(node.val)
# 先右后左,保证出栈顺序是 根 -> 左 -> 右
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return result
2.中序
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
stack = []
result = []
cur = root
while cur or stack:
# 一直向左走,将路径上的节点压入栈
if cur:
stack.append(cur)
cur = cur.left
else:
# 左子树访问完后,开始处理根节点
cur = stack.pop()
result.append(cur.val)
# 转向右子树
cur = cur.right
return result
3.后序
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
stack = [root]
result = []
while stack:
node = stack.pop()
result.append(node.val)
# 先左后右,这样在反转后得到左 -> 右 -> 根的顺序
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
return result[::-1]
七、层序遍历
层序遍历(广度优先遍历)是一种按照从上到下、从左到右的顺序遍历二叉树的方式。使用队列来辅助实现层序遍历,因为队列遵循先进先出(FIFO)的特性,可以很好地支持按层遍历。
102.二叉树的层序遍历
# 迭代解法
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if not root: # 空树直接返回空列表
return []
queue = collections.deque([root]) # 初始化队列,将根节点入队
result = [] # 用于存储按层的遍历结果
while queue:
level = [] # 临时列表,用于存储当前层的节点值
# 遍历当前层的所有节点
for _ in range(len(queue)):
cur = queue.popleft() # 从队列中弹出节点
level.append(cur.val) # 添加节点值到当前层的结果列表中
# 将当前节点的左子节点和右子节点加入队列
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
result.append(level) # 将当前层的结果添加到最终结果中
return result # 返回按层的节点值
#递归解法
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if not root:
return []
levels = [] # 存储每一层的节点值
def traverse(node, level):
if not node:
return
# 当 levels 长度等于当前 level 时,添加一个新的层级列表
if len(levels) == level:
levels.append([])
# 将当前节点的值添加到当前层级对应的列表中
levels[level].append(node.val)
# 递归地处理左子树和右子树,并增加层级
traverse(node.left, level + 1)
traverse(node.right, level + 1)
# 从根节点开始递归,初始层级为 0
traverse(root, 0)
return levels
107.二叉树的层次遍历 II
上一题解法返回result[::-1]
199.二叉树的右视图
class Solution:
def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
queue = deque([root]) # 初始化队列,将根节点入队
result = [] # 用于存储右视图的节点值
while queue:
level_length = len(queue) # 当前层的节点数
for i in range(level_length):
node = queue.popleft() # 弹出当前层的节点
# 如果是该层的最后一个节点,添加到结果中
if i == level_length - 1:
result.append(node.val)
# 将左右子节点加入队列,以便遍历下一层
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
637.二叉树的层平均值
class Solution:
def averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
if not root:
return []
queue = collections.deque([root])
average = []
while queue:
level_size = len(queue)
level_sum = 0
for i in range(level_size):
node = queue.popleft()
level_sum += node.val
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
average.append(level_sum/level_size)
return average
429.N叉树的层序遍历
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
if not root:
return []
result = []
queue = collections.deque([root])
while queue:
level_size = len(queue)
level = []
for _ in range(level_size):
node = queue.popleft()
level.append(node.val)
for child in node.children:
queue.append(child)
result.append(level)
return result
515.在每个树行中找最大值
class Solution:
def largestValues(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
result = []
queue = collections.deque([root])
while queue:
level_size = len(queue)
max_val = float('-inf')
for _ in range(level_size):
node = queue.popleft()
max_val = max(max_val, node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.append(max_val)
return result
116.填充每个节点的下一个右侧节点指针
题目:每行的左node指向右node,最右边的指向null

class Solution:
def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
if not root:
return root
queue = collections.deque([root])
while queue:
level_size = len(queue)
prev = None
for i in range(level_size):
node = queue.popleft()
# 如果已经有指向,使得前一个指向新的
if prev:
prev.next = node
# 没有就赋值到当前node上
prev = node
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return root
104.二叉树的最大深度
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return root
queue = collections.deque([root])
depth = 0
while queue:
depth += 1
for i in range(len(queue)):
node = queue.popleft()
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return depth
111.二叉树的最小深度
只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点
class Solution:
def minDepth(self, root: TreeNode) -> int:
if not root:
return 0
depth = 0
queue = collections.deque([root])
while queue:
depth += 1
for _ in range(len(queue)):
node = queue.popleft()
if not node.left and not node.right:
return depth
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return depth


4万+

被折叠的 条评论
为什么被折叠?



