排序二叉树中存在一个问题就是可能会退化成一个链表,当只有左子树或者右子树有节点的时候,此时排序二叉树就像链表一样,但因为排序二叉树在插入查询的时候还要判断左右子树的问题,这样查询的效率反而变低,从而引出了平衡二叉树
平衡二叉树又称平衡搜索树(Self-balance Binary Search Tree)又称AVL树,同时保证了查询和添加的效率。首先平衡二叉树是一颗排序二叉树,且它是空树或者他的每一个节点分支的左右两颗子树的高度差值的绝对值小于等于1。平衡二叉树的实现方法主要有红黑树,AVL,替罪羊树,Treap,伸展树等
class Node(object):
def __init__(self, data):
self.data = data
self.parent = None
self.left = None
self.right = None
def __str__(self):
return str(self.data)
def add(self, node):
if self.data > node.data:
if self.left is None:
self.left = node
node.parent = self
else:
self.left.add(node)
else:
if self.right is None:
self.right = node
node.parent = self
else:
self.right.add(node)
if self.left_height() - self.right_height() > 1:
# 左高右低 右旋转
if self.left is not None and self.left.right_height() > self.left.left_height():
# 如果目标节点的左子树的右子树的高度大于目标节点的右子树高度 需要先进行左旋转
self.left_rotate()
self.right_rotate()
if self.right_height() - self.left_height() > 1:
# 右高左低 左旋转self.left.left
if self.right is not None and self.right.left_height() > self.right.right_height():
self.right_rotate()
self.left_rotate()
def height(self):
"""
获取树的高度
:return:
"""
return max(self.left.height() if self.left is not None else 0,
self.right.height() if self.right is not None else 0) + 1
def left_height(self):
return 0 if self.left is None else self.left.height()
def right_height(self):
return 0 if self.right is None else self.right.height()
def pre_order(self):
"""
前序遍历
:return:
"""
print(self, end='->')
if self.left is not None:
self.left.pre_order()
if self.right is not None:
self.right.pre_order()
def in_order(self):
"""
中序遍历
:return:
"""
if self.left is not None:
self.left.in_order()
print(self, end='->')
if self.right is not None:
self.right.in_order()
def post_order(self):
"""
后续遍历
:return:
"""
if self.left is not None:
self.left.post_order()
if self.right is not None:
self.right.post_order()
print(self, end='->')
def find(self, data):
"""
查找
:param data:
:return:
"""
if self.data == data:
return self
elif data > self.data:
# 右找
return self.right.find(data)
else:
return self.left.find(data)
def find_min(self):
"""
找到一某一个节点为根节点的左小值
:return:
"""
if self.left is not None:
temp = self
while temp.left is not None:
temp = temp.left
return temp
return self
def is_leaf(self):
"""
判断当前节点是否是叶子节点
:return:
"""
return self.left is None and self.right is None
def delete(self, data):
"""
- 先找到待删除节点,因为现在树是单向的需要把待删除节点的父节点也找到
- 如果待删除节点是一个叶子节点,判断待删除节点是父节点的左节点还是右节点,找到之后相应指针置空即可
- 如果待删除节点是一个非叶子节点,且只有一颗子树的情况
- 首先确定待删除节点的子树是左子树还是右子树,为了下一步挂到父节点上
- 再确定待删除节点是父节点的左节点还是右节点,把之前确定的子树挂在对应的节点上l
- 因为根节点没有父节点需要做特殊处理
- 如果待删除节点是一个非叶子节点,且有两颗子树的情况
- 从待删除节点的右子树中找到最小的一个节点,或者从待删除节点左子树找到最大的一个节点
- 删除在子树中找到的这个节点
- 将待删除节点的值替换成刚才删除的节点的值即可形成新的顺序二叉树
:return:
"""
# 先找到待删除节点,因为现在树是单向的需要把待删除节点的父节点也找到
target_node = self.find(data)
if target_node is None:
return
else:
# 如果待删除节点是一个叶子节点,判断待删除节点是父节点的左节点还是右节点,找到之后相应指针置空即可
parent = target_node.parent
if target_node.is_leaf():
if parent.left is target_node:
target_node.parent.left = None
if parent.right is target_node:
target_node.parent.right = None
else:
# 存在子树的情况
if target_node.left is not None and target_node.right is not None:
# 如果待删除节点是一个非叶子节点,且有两颗子树的情况
# 从待删除节点的右子树中找到最小的一个节点,或者从待删除节点左子树找到最大的一个节点
min_node = target_node.right.find_min()
# 删除在子树中找到的这个节点
self.delete(min_node.data)
# 将待删除节点的值替换成刚才删除的节点的值即可形成新的顺序二叉树
target_node.data = min_node.data
else:
# 如果待删除节点是一个非叶子节点,且只有一颗子树的情况
if parent is not None:
# 首先确定待删除节点的子树是左子树还是右子树,为了下一步挂到父节点上
# 再确定待删除节点是父节点的左节点还是右节点,把之前确定的子树挂在对应的节点上
if parent.left is target_node and target_node.left is not None:
parent.left = target_node.left
elif parent.right is target_node and target_node.left is not None:
parent.right = target_node.left
elif parent.left is target_node and target_node.right is not None:
parent.left = target_node.right
elif parent.right is target_node and target_node.right is not None:
parent.right = target_node.right
else:
# 因为根节点没有父节点需要做特殊处理
pass
def right_rotate(self):
"""
右旋转
:return:
"""
temp = Node(self.data)
temp.right = self.right
self.data = self.left.data
self.left = self.left.left
self.right = temp
def left_rotate(self):
"""
左旋转
:return:
"""
temp = Node(self.data)
temp.left = self.left
self.data = self.right.data
self.right = self.right.right
self.left = temp
class BinaryTree(object):
def __init__(self):
self.root = None
def add(self, node):
if self.root is None:
self.root = node
else:
self.root.add(node)
def pre_order(self):
if self.root is not None:
self.root.pre_order()
print()
def in_order(self):
if self.root is not None:
self.root.in_order()
print()
else:
raise Exception('tree is empty!')
def post_order(self):
if self.root is not None:
self.root.post_order()
print()
def find(self, data):
if self.root is None:
return
else:
self.root.find(data)
def delete(self, data):
if self.root is None:
return
elif self.root.data == data and self.root.left is None and self.root.right is None:
self.root = None
return
else:
self.root.delete(data)
def height(self):
return 0 if self.root is None else self.root.height()
if __name__ == '__main__':
binary_tree = BinaryTree()
# for i in range(1, 6):
# binary_tree.add(Node(random.randint(0, 25)))
# binary_tree.pre_order()
# print()
# binary_tree.in_order()
# print()
# binary_tree.post_order()
# 测试删除
# arr = [7, 3, 10, 12, 5, 1, 9, 2]
# for i in arr:
# binary_tree.add(Node(i))
# binary_tree.in_order()
# # binary_tree.delete(5)
# # binary_tree.in_order()
# binary_tree.delete(10)
# binary_tree.in_order()
# binary_tree.delete(2)
# binary_tree.in_order()
# binary_tree.delete(3)
# binary_tree.in_order()
# binary_tree.delete(1)
# binary_tree.in_order()
# binary_tree.delete(7)
# binary_tree.in_order()
# binary_tree.delete(9)
# binary_tree.in_order()
# binary_tree.delete(5)
# binary_tree.in_order()
# binary_tree.delete(12)
# binary_tree.in_order()
# 测试旋转
binary_tree.add(Node(7))
binary_tree.add(Node(5))
binary_tree.add(Node(4))
print(binary_tree.height())
binary_tree.add(Node(3))
binary_tree.add(Node(8))
binary_tree.pre_order()