基本概述
- 如何更加高效的完成对数据的查询和添加操作,例如↓↓↓
- 之前解决方案的优缺点
- 树结构解决方案:二叉排序树
二叉排序树的创建和遍历
class TreeNode(object):
def __init__(self, val):
self.val = val
self.left = None
self.right = None
class BinarySortTree(object):
def __init__(self):
self.root = None
# 添加结点
def add(self, val):
node = TreeNode(val)
if self.root is None:
self.root = node
return
queue = [self.root]
while queue:
temp_node = queue.pop(0)
# 判断传入结点的值和当前子树结点的值关系
if node.val < temp_node.val:
if temp_node.left is None:
temp_node.left = node
return
else:
queue.append(temp_node.left)
if node.val >= temp_node.val:
if temp_node.right is None:
temp_node.right = node
return
else:
queue.append(temp_node.right)
# 中序遍历
def in_order(self, node):
if node is None:
return
self.in_order(node.left)
print(node.val, end=" ")
self.in_order(node.right)
if __name__ == '__main__':
t = BinarySortTree()
note_array = [7, 3, 10, 12, 5, 1, 9]
for item in note_array:
t.add(item)
t.in_order(t.root)
'''输出结果
1,3,5,7,9,10,12
刚好是升序
'''
二叉排序树的删除
删除时会遇到的情况
-
要处理的各种情况
-
第一种情况:删除叶子结点
-
第二种情况:删除只有一棵子树的结点
-
第三种情况:删除有两课子树的结点
(1)上图为,target_node的右子树只有一个结点,那它就是最小的
(2)下图,假设当target_node的右子树,还有一个11,那么11就是最小的,需要把11的值放到target_node的位置
先实现查找要删除的结点
'''上面代码一样,先省略'''
def search(self, node, val):
'''
:param node: 传入根结点
:param val: 传入要查找的值
:return: 找到返回该node,没找到返回None
'''
if node is None:
return None
if node.val == val:
return node
if val < node.val:
return self.search(node.left, val)
else:
return self.search(node.right, val)
if __name__ == '__main__':
t = BinarySortTree()
note_array = [7, 3, 10, 12, 5, 1, 9]
for item in note_array:
t.add(item)
search_node =t.search(t.root, 3) # 3
if search_node: # 只为测试用
print(search_node.val)
else:
print(search_node)
查找要删除节点的父结点
'''上面代码一样,先省略'''
# 查找结点的父结点
def parent(self, node, val):
'''
:param node: 传入根结点
:param val: 传入要找的父结点的值
:return: 如果找到返回该父结点,如果没有返回None
'''
if node is None: # 如果要找的值遍历完二叉树还不存在,由此退出并返回None
return None
if self.root.val == val: # 根结点没有父结点
return None
# 如果当前结点的左子结点或者右子结点存在,并且值就是要找的,直接返回它的父结点
if (node.left and node.left.val == val) or (node.right and node.right.val == val):
return node
else:
# 如果要找的结点值小于父结点且它的左子结点存在,向左递归
if val < node.val and node.left:
return self.parent(node.left, val)
# 如果要找的结点值大于父结点且它的右子结点存在,向左递归
elif node.val < val and node.right:
return self.parent(node.right, val)
if __name__ == '__main__':
t = BinarySortTree()
note_array = [7, 3, 10, 12, 5, 1, 9]
for item in note_array:
t.add(item)
# t.in_order(t.root)
# print(t.search(t.root, 3))
parent_node = t.parent(t.root, 1) # 3
if parent_node: # 只为输出测试
print(parent_node.val)
else:
print(parent_node)
完整实现二叉排序树的删除结点操作
class TreeNode(object):
def __init__(self, val):
self.val = val
self.left = None
self.right = None
class BinarySortTree(object):
def __init__(self):
self.root = None
# 添加结点
def add(self, val):
node = TreeNode(val)
if self.root is None:
self.root = node
return
queue = [self.root]
while queue:
temp_node = queue.pop(0)
# 判断传入结点的值和当前子树结点的值关系
if node.val < temp_node.val:
if temp_node.left is None:
temp_node.left = node
return
else:
queue.append(temp_node.left)
if node.val >= temp_node.val:
if temp_node.right is None:
temp_node.right = node
return
else:
queue.append(temp_node.right)
# 中序遍历
def in_order(self, node):
if node is None:
return
self.in_order(node.left)
print(node.val, end=" ")
self.in_order(node.right)
# 删除节点
def del_node(self, node, val):
'''
:param node: 传入根结点
:param val: 传入要删除结点的值
:return:
'''
if node is None:
return
# 先去找到要删除的结点
target_node = self.search(node, val)
if target_node is None: # 如果没有找到要删除的结点
return
# 如果发现当前这棵二叉排序树只有一个结点
if node.left is None and node.right is None:
self.root = None # 根结点直接置空
return
# 去找到target_node的父结点
parent = self.parent(node, val)
# 删除的结点是叶子结点
if target_node.left is None and target_node.right is None:
# 判断target_node 是父结点的左子结点,还是右子结点
if parent.left and parent.left.val == val: # target_node 是左子结点
parent.left = None
elif parent.right and parent.right.val == val: # target_node 是右子结点
parent.right = None
elif target_node.left and target_node.right: # 删除有两颗子树的结点
min_val = self.del_right_tree_min(target_node.right)
target_node.val = min_val
else: # 删除只有一颗子树的结点
if target_node.left: # 如果要删除的结点target_node有左子结点
if parent: # 如果target_node有父结点
if parent.left.val == val: # target_node是parent左子结点
parent.left = target_node.left
else: # parent.right.val == val,即是target_node是parent右子结点
parent.right = target_node.left
else:
self.root = target_node.left
else: # 如果要删除的结点target_node有右子结点
if parent: # 如果target_node有父结点
if parent.left.val == val:
parent.left = target_node.right
else: # parent.right.val == val,即是target_node是parent右子结点
parent.right = target_node.right
else:
self.root = target_node.right
# 查找结点
def search(self, node, val):
'''
:param node: 传入根结点
:param val: 传入要查找的值
:return: 找到返回该值,没找到返回None
'''
if node is None:
return None
if node.val == val:
return node
if val < node.val:
return self.search(node.left, val)
else:
return self.search(node.right, val)
# 查找结点的父结点
def parent(self, node, val):
'''
:param node: 传入根结点
:param val: 传入要找的父结点的值
:return: 如果找到返回该父结点,如果没有返回None
'''
if node is None: # 如果要找的值遍历完二叉树还不存在,由此退出并返回None
return None
if self.root.val == val: # 根结点没有父结点
return None
# 如果当前结点的左子结点或者右子结点存在,并且值就是要要找的,直接返回它的父结点
if (node.left and node.left.val == val) or (node.right and node.right.val == val):
return node
else:
# 如果要找的结点值小于父结点且它的左子结点存在,向左递归
if val < node.val and node.left:
return self.parent(node.left, val)
# 如果要找的结点值大于父结点且它的右子结点存在,向左递归
elif node.val < val and node.right:
return self.parent(node.right, val)
def del_right_tree_min(self, node):
# 从target_node的右子树出发,查找它的左边最小结点,并返回删除结点的值
# 作用1:返回以node为根结点的二叉排序树的最小结点
# 作用2:删除 node 为根结点的二叉排序树的最小结点
temp_node = node
# 循环的查找左结点,直到找到最小值
while temp_node.left:
temp_node = temp_node.left
# 这时 target就指向了最小结点
# 调用删除方法,删除最小结点
self.del_node(self.root, temp_node.val) # 注意传入的还是跟结点,从根结点开始查找
return temp_node.val
if __name__ == '__main__':
t = BinarySortTree()
note_array = [7, 3, 10, 12, 5, 1, 9, 2]
for item in note_array:
t.add(item)
'''# 测试:删除叶子结点
t.del_node(t.root, 2)
t.del_node(t.root, 5)
t.del_node(t.root, 9)
t.del_node(t.root, 12)
t.in_order(t.root) # 1 3 7 10
'''
'''# 测试:删除只有一颗子树的结点
t.del_node(t.root, 1)
t.in_order(t.root) # 2 3 5 7 9 10 12
'''
# 测试:删除有两颗子树的结点
# t.del_node(t.root, 7)
# t.in_order(t.root) # 1 2 3 5 9 10 12
# t.del_node(t.root, 10)
# t.in_order(t.root) # 1 2 3 5 7 9 12
# t.in_order(t.root)
# 连续删除任意结点测试:
t.del_node(t.root, 2)
t.del_node(t.root, 5)
t.del_node(t.root, 9)
t.del_node(t.root, 12)
t.del_node(t.root, 7)
# t.del_node(t.root, 3)
# t.del_node(t.root, 10)
# t.del_node(t.root, 1)
t.in_order(t.root)