二叉树
二叉树种类
二叉树有两种主要的形式:满二叉树和完全二叉树。
满二叉树
满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
这棵二叉树为满二叉树,也可以说深度为k=4,有2^k-1=15个节点的二叉树。
完全二叉树
**完全二叉树:**在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h -1个节点。
二叉搜索树
二叉搜索树是有数值的了,二叉搜索树是一个有序树。
- 若它的左子树不空,则左子树上所有结点的值均小(大)于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大(小)于它的根结点的值;
- 它的左、右子树也分别为二叉排序树。
平衡二叉搜索树
平衡二叉搜索树:AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
二叉树存储
二叉树可以链式存储(类似指针的方式),也可以顺序存储(列表)。
链式存储
顺序存储
二叉树遍历
二叉树主要有两种遍历方式:
-
深度优先遍历:先往深走,遇到叶子节点再往回走。
前序遍历(递归法,迭代法)
中序遍历(递归法,迭代法)
后序遍历(递归法,迭代法) -
广度优先遍历:一层一层的去遍历。
层次遍历(迭代法)
深度优先遍历
from collections import deque
# 节点类
class TreeNode(object):
def __init__(self, val):
self.val = val
self.left_child = None
self.right_child = None
# 构建完全二叉树
class BinaryTree(object):
def __init__(self, val=None):
self.root = TreeNode(val)
def add(self, item):
"""
二叉树添加一个节点,每一层从左到右遍历获取可以添加节点的位置,保证完全二叉树的性质
:param item: 节点数据
:return:
"""
if not self.root:
self.root = TreeNode(item)
return
# 采用广度优先一层一层遍历(从左到右)找到空置的节点添加
dq = deque([self.root])
while dq:
cur = dq.popleft()
if not cur.left_child:
cur.left_child = TreeNode(item)
return
if not cur.right_child:
cur.right_child = TreeNode(item)
return
if cur.left_child:
dq.append(cur.left_child)
if cur.right_child:
dq.append(cur.right_child)
def _get_parent(self, item):
"""
返回 值为item的节点的父节点
:param item:
:return:
"""
if self.root.val == item:
return None, None
# 采用广度优先一层一层遍历(从左到右)找到空置的节点添加
dq = deque([self.root])
while dq:
cur = dq.popleft()
if cur.left_child and cur.left_child.val == item:
return "left", cur
if cur.right_child and cur.right_child.val == item:
return "right", cur
if cur.left_child:
dq.append(cur.left_child)
if cur.right_child:
dq.append(cur.right_child)
return None, None
def delete(self, item):
"""
删除值为item的节点
:param item: 待删除的节点值
:return:
"""
if not self.root:
return False
site, parent = self._get_parent(item)
if parent:
cur = parent.left_child if site == "left" else parent.right_child
# 1. cur节点没有子节点,则直接将父节点的子节点置为None
if not cur.left_child and not cur.right_child:
if site == "left":
parent.left_child = None
else:
parent.right_child = None
return True
# 2. cur节点有一个子节点,则将子节点和父节点直接链接
elif (not cur.left_child and cur.right_child) or \
(cur.left_child and not cur.right_child):
cur_child = cur.left_child if cur.left_child else cur.right_child
if site == "left":
parent.left_child = cur_child
else:
parent.right_child = cur_child
# 3. cur存在两个子节点,找到cur的左右子树中最左边的叶子节点替换cur节点,保证完全二叉树性质
else:
dq = deque([cur])
replace_par_node = ("", None)
while dq:
node = dq.popleft()
# 左节点存在右节点不存在,则左节点即为最下面一层最靠右的叶子节点
if node.left_child and not node.right_child:
replace_par_node = ("left", node)
break
# 记录最后一个左右子节点都存在的情况,如果是最后一层子节点都是满的,
# 那么要替换的就是最右边的节点
if node.left_child and node.right_child:
replace_par_node = ("right", node)
if node.left_child:
dq.append(node.left_child)
if node.right_child:
dq.append(node.right_child)
if replace_par_node[0] == "left":
replace_node = replace_par_node[1].left_child
replace_par_node[1].left_child = None
else:
replace_node = replace_par_node[1].right_child
replace_par_node[1].right_child = None
cur.val = replace_node.val
return True
else:
return False
# 前序遍历---递归
def recursion_preorder(self):
result = []
self._preorder(self.root, result)
return result
def _preorder(self, root, result):
if not root:
return []
result.append(root.val)
self._preorder(root.left_child, result)
self._preorder(root.right_child, result)
# 前序遍历
def preorder(self):
stack = deque()
cur = self.root
result = []
while cur or stack:
# 前序遍历:中左右,先从根节点一直向左遍历,遍历过程中每个节点都加入result,
# 直到叶子结点,再获取每个节点的右子节点。
while cur:
stack.append(cur)
result.append(cur.val)
cur = cur.left
cur = stack.pop()
cur = cur.right
return result
# 中序遍历---递归
def recursion_inorder(self):
result = []
self._inorder(self.root, result)
return result
def _inorder(self, root, result):
if not root:
return []
self._inorder(root.left_child, result)
result.append(root.val)
self._inorder(root.right_child, result)
# 中序遍历
def inorder(self):
result = []
stack = deque()
cur = self.root
while cur or stack:
# 中序遍历: 左中右,从根节点开始向左遍历,直到叶子节点,其中每个节点都入栈
# 到达叶子节点后,从栈中取出节点加入result
while cur:
stack.append(cur)
cur = cur.left
cur = stack.pop()
result.append(cur.val)
cur = cur.right
return result
# 后序遍历---递归
def recursion_postorder(self):
result = []
self._postorder(self.root, result)
return result
def _postorder(self, root, result):
if not root:
return []
self._postorder(root.left_child, result)
self._postorder(root.right_child, result)
result.append(root.val)
# 后序遍历
def postorder(self):
stack = deque()
cur = self.root
result = []
# 后序遍历: 左右中
# 前序遍历: 中左右,所以只需要得到中右左,再反转就得了左右中
while cur or stack:
while cur:
stack.append(cur)
result.append(cur.val)
cur = cur.right
cur = stack.pop()
cur = cur.left
result.reverse()
return result
if __name__ == '__main__':
b = BinaryTree(13)
b.add(12)
b.add(18)
b.add(7)
b.add(11)
b.add(14)
b.add(17)
b.add(3)
b.add(8)
b.add(9)
b.add(10)
b.delete(10)
b.delete(9)
b.delete(11)
print(b.preorder())
print(b.recursion_preorder())
print(b.inorder())
print(b.recursion_inorder())
print(b.postorder())
print(b.recursion_postorder())
LeetCode
589. N 叉树的前序遍历
解一:递归
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def preorder(self, root: 'Node') -> List[int]:
result = []
self._preorder(root, result)
return result
def _preorder(self, root, result):
if not root:
return []
result.append(root.val)
for child in root.children:
self._preorder(child, result)
解二:迭代
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def preorder(self, root: 'Node') -> List[int]:
if not root:
return []
result = []
stack = deque([root])
while stack:
cur = stack.pop()
result.append(cur.val)
# 倒序遍历每个子节点
for i in range(len(cur.children)-1, -1, -1):
stack.append(cur.children[i])
return result
590. N 叉树的后序遍历
解一:递归
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def postorder(self, root: 'Node') -> List[int]:
result = []
self._postorder(root, result)
return result
def _postorder(self, root, result):
if not root:
return []
for child in root.children:
self._postorder(child, result)
result.append(root.val)
解二:迭代
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def postorder(self, root: 'Node') -> List[int]:
if not root:
return root
result = []
stack = deque([root])
# 先序遍历是"中左右",后续遍历是"左中右";
# 则调整代码左右顺序,然后将结果result反转就得到左右中。
while stack:
cur = stack.pop()
result.append(cur.val)
for child in cur.children:
stack.append(child)
result.reverse()
return result
102. 二叉树的层序遍历
解:广度优先
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
result = []
# 层序遍历,采用广度优先
dq = deque()
# 第二个参数标记是否同一层
dq.append((root, 0))
temp = []
while dq:
cur, flag = dq.popleft()