Height Balance:
- maintain the height of the tree is
- AVL Tree
Rotations:
Change the subtree's height without changing the traversal order .
def subtree_rotate_right(D):
assert D.left
B, E = D.left, D.right
A, C = B.left, B.right
D, B = B, D
D.item, B.item = B.item, D.item
B.left, B.right = A, D
D.left, D.right = C, E
if A: A.parent = B
if E: E.parent = D
AVL Trees: hight balance
AVL trees maintain the height-balance,which calls the AVL Property.
- left and right subtree's height differ by most 1
Df:
def subtree_rotate_right(D):
assert D.left
B, E = D.left, D.right
A, C = B.left, B.right
D, B = B, D
D.item, B.item = B.item, D.item
B.left, B.right = A, D
D.left, D.right = C, E
if A: A.parent = B
if E: E.parent = D
def skew(A):
return height(A.right) - height(A.left)
def rebalance(A):
if skew(A) == 2:
if A.right.skew() < 0:
A.right.subtree_rotate_right()
A.subtree_rotate_left()
elif skew(A) == -2:
if A.left.skew() > 0:
A.left.subtree_rotate_left()
A.subtree_rotate_right()
def maintain(A):
A.rebalance
if A.parent:
A.parent.maintain()
Height:
If we want to compute the skew of the tree,the heght of the subtree is essential.
And if we want to rebalance the tree in time,we need to compute each node's height in . Instead of computing each node's height every time we need ,we speed up the computation via augmentation.
def height(A):
if A is None: return -1
return 1 + max(height(A.left), height(A.right))
# Why if A is None,we will return -1
# When A is a leaf node(A doesn't have the subtree), we will return " 1+ -1 == 0 "
# the zero results that,we won't plus 1 to the hieght.
# Samely the root node's height is 0.
def height(A):
if A:
return height(A)
else:
return -1
def subtree_update(A):
A.height = 1 + max(height(A.left), height(A.right))
Full inplementation with AVL balancing:
def height(A):
if A:
return A.height
else:
return -1
class Binary_Node():
def __init__(self, A, x):
A.item = x
A.left = None
A.right = None
A.parent = None
A.subtree_update()
def subtree_update(self, A):
A.height = 1 + max(height(A.left), height(A.right))
def skew(self, A):
return height(A.right) - height(A.left)
def subtree_iter(selfA):
if A.left: yield from A.left.subtree_iter()
yield A
if A.right: yield from A.right.subtree_iter()
def subtree_first(A):
if A.left:
return A.left.subtree_first()
else:
return A
def subtree_last(A):
if A.right:
return A.right.subtree_last()
else:
return A
def successor(A):
if A.right:
return A.right.subtree_first
while A.parent and (A is A.parent.right):
A = A.parent
return A.parent
def predecessor(A):
if A.left:
return A.left.subtree_last()
while A.parent and (A is A.parent.left):
A = A.parent
return A.parent
def subtree_insert_before(A, B):
if A.left:
A = A.left.subtree_last()
A.right, B.parent = B, A
else:
A.left, B.parent = B, A
A.maintain()
def subtree_insert_after(A, B):
if A.right:
A = A.right.subtree_first()
A.left, B.parent = B, A
else:
A.right, B.parent = B, A
A.maintain()
def subtree_delete(A):
if A.left or A.right:
if A.left:
B = A.predecessor()
else:
B = A.successor()
A.item, B = item = B.item, A.item
return B.subtree_delete()
if A.parent:
if A.parent.left is A:
A.parent.left is None
else:
A.parent.right is None
A.parent.maintain()
return A.parent
def subtree_rotate_right(D):
assert D.left
B, E = D.left, D.right
A, C = B.left, B.right
B, D = D, B
D.item, B.item = B.item, D.item
B.left, B.right = A, D
D.left, D.right = C, E
if A: A.parent = B
if E: E.parent = D
B.subtree_maintain()
D.subtree_maintain()
def rebalance(A):
if A.skew() == 2:
if A.right.skew() < 0:
A.left.subtree_rotate_right()
A.subtree_rotate_left()
elif A.skew == -2:
if A.left.skew() > 0:
A.left.subtree_rotate_left()
A.subtree_rotate_right()
def maintain(A):
A.rebalance()
A.subtree_update()
if A.parent():
A.parent.maintain()
Sequence Application:
class Size_Node(Binary_Node):
def subtree_update(self, A):
super().subtree_update()
A.size = 1
if A.left: A.size += A.left.size
if A.right: A.size += A.right.size
def subtree_at(self, A, i):
assert i >= 0
if A.left:
L_size = A.left.size
else:
L_size = 0
if i < L_size:
return A.left.subtree_at(i)
elif i > L_size:
return A.right.subtree_at(i - L_i - 1)
else:
return A