AVL数是一棵自平衡的二叉搜索树。数的每一个节点的左右子树高度差绝对值不能超过1.
如果某一个节点的左右子树的高度差绝对值等于2时,则二叉树需要自平衡操作:
class BiTreeNode(): # 定义二叉树型节点
def __init__(self,val):
self.data = val
self.lchild = None
self.rchild = None
self.parent = None
self.bf = None
class AVLTree(): # 定义AVL数对象
def __init__(self):
self.root = None
def node_depth(self,node): # 计算以节点node为根的数高度
if not node:
return 0
if not node.lchild and not node.rchild:
return 1
else:
ml = self.node_depth(node.lchild)+1
mr = self.node_depth(node.rchild)+1
return max(ml,mr)
def bf_update(self,node): # 更新节点的balance factor
flag_change2zero = 0
if not node:
return 0, flag_change2zero
else:
ml = self.node_depth(node.lchild)
mr = self.node_depth(node.rchild)
bf = ml - mr
if node.bf and bf == 0: # 如果该节点的bf变化为0,则该节点的父节点的bf值将不受影响
flag_change2zero = 1
return bf,flag_change2zero
def rotate_left(self,node_f,node_s): # 左旋
if node_f.parent: # 判断旋转之前的node_f节点是否有父节点,有的话需要将旋转后的节点与父节点相连
node_gf = node_f.parent
else:
node_gf = None
node_gs = node_s.lchild
node_f.rchild = node_gs
if node_gs:
node_gs.parent = node_f
node_s.lchild = node_f
node_f.parent = node_s
return node_s,node_gf
def rotate_right(self,node_f,node_s): # 右旋
if node_f.parent:
node_gf = node_f.parent
else:
node_gf = None
node_gs = node_s.rchild
node_f.lchild = node_gs
if node_gs:
node_gs.parent = node_f
node_s.rchild = node_f
node_f.parent = node_s
return node_s,node_gf
def rotate_right_left(self,node_f,node_s): # 先右旋再左旋
if node_f.parent:
node_gf = node_f.parent
else:
node_gf = None
node_gs = node_s.lchild
node_ggs = node_gs.rchild
node_s.lchild = node_ggs
if node_ggs:
node_ggs.parent = node_s
node_gs.rchild = node_s
node_s.parent = node_gs
node_ggs = node_gs.lchild
node_f.rchild = node_ggs
if node_ggs:
node_ggs.parent = node_f
node_gs.lchild = node_f
node_f.parent = node_gs
return node_gs,node_gf
def rotate_left_right(self,node_f,node_s): # 先左旋再右旋
if node_f.parent:
node_gf = node_f.parent
else:
node_gf = None
node_gs = node_s.rchild
node_ggs = node_gs.lchild
node_s.rchild = node_ggs
if node_ggs:
node_ggs.parent = node_s
node_gs.lchild = node_s
node_s.parent = node_gs
node_ggs = node_gs.rchild
node_f.lchild = node_ggs
if node_ggs:
node_ggs.parent = node_f
node_gs.rchild = node_f
node_f.parent = node_gs
return node_gs,node_gf
def insert(self,val): # 插入节点
if not self.root:
self.root = BiTreeNode(val)
self.root.bf = 0
return self.root
node = self.root
while True:
if val < node.data:
if node.lchild:
node = node.lchild
else:
node_new = BiTreeNode(val)
node.lchild = node_new
node_new.parent = node
break
else:
if node.rchild:
node = node.rchild
else:
node_new = BiTreeNode(val)
node.rchild = node_new
node_new.parent = node
break
node = node_new
node_order = [] # 用来表示引起变化的节点的来源,来源于左子树,存1,来源与右子树,存-1
flag_rotate = 0
while True: # 节点插入完毕后对节点的bf进行更新。
node.bf, flag_change2zero = self.bf_update(node)
if node.bf == -2 or node.bf == 2: # 遇到某一节点的bf变为2或-2时,停止更新,进行自平衡操作。
node_f = node
flag_rotate = 1
break
if not node.parent or flag_change2zero == 1: # 更新到根节点或某一节点的bf变为0,则停止更新。
break
else:
if node.parent.lchild == node:
node_order.append(1)
else:
node_order.append(-1)
node = node.parent
if flag_rotate: # 进行自平衡操作。
if node_order[-1] == -1:
if node_order[-2] == -1: # 右右,要左旋
node, node_gf = self.rotate_left(node_f, node_f.rchild)
node.bf = self.bf_update(node)[0]
node.lchild.bf = self.bf_update(node.lchild)[0]
else: # 右左,先右旋,再左旋
node, node_gf = self.rotate_right_left(node_f,node_f.rchild)
node.bf = self.bf_update(node)[0]
node.lchild.bf = self.bf_update(node.lchild)[0]
node.rchild.bf = self.bf_update(node.rchild)[0]
else:
if node_order[-2] == 1: # 左左,要右旋
node, node_gf = self.rotate_right(node_f, node_f.lchild)
node.bf = self.bf_update(node)[0]
node.rchild.bf = self.bf_update(node.rchild)[0]
else: # 左右,先左旋,再右旋
node, node_gf = self.rotate_left_right(node_f, node_f.lchild)
node.bf = self.bf_update(node)[0]
node.lchild.bf = self.bf_update(node.lchild)[0]
node.rchild.bf = self.bf_update(node.rchild)[0]
if node_gf: # 如果旋转之前的节点有父节点,进行父节点链接。
if node_gf.lchild == node_f:
node_gf.lchild = node
node.parent = node_gf
else:
node_gf.rchild = node
node.parent = node_gf
else: # 如果旋转之前的节点没有父节点,则root节点要在旋转之中,此时需要更新root节点
node.parent = None
self.root = node
return self.root
def pre_order(self,root):
if root:
print(root.data,root.bf, end=' ')
self.pre_order(root.lchild)
self.pre_order(root.rchild)
def in_order(self,root):
if root:
self.in_order(root.lchild)
print(root.data,root.bf, end=' ')
self.in_order(root.rchild)
AVL数的搜索与删除操作与二叉搜索数一样。删除时需要考虑删除节点的类型:
(1)如果删除的节点为叶子节点,则直接删除。
(2)如果删除的节点只有左子树或右子树,将左子树或右子树直接连于删除节点的父节点,此时需要考虑删除节点是根节点的情况。
(3)如果删除节点有左子树和右子树,此时需要从删除节点的右子树中找值最小的节点放于删除节点的位置。
删除节点后,需要对删除后相关节点的bf进行更新,并进行自平衡操作。