fix(wavl): propagate root rotation to the helper functions for delete

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2022-05-07 15:42:37 +02:00
parent 457ab180d0
commit 2433928d36
Signed by: mfocko
GPG key ID: 7C47D46246790496

54
wavl.py
View file

@ -29,15 +29,16 @@ class WAVLTree(AVLTree[T]):
# region DeleteRebalance # region DeleteRebalance
@staticmethod
def __fix_delete( def __fix_delete(
self,
x: Optional[Node[T]], x: Optional[Node[T]],
y: Node[T], y: Node[T],
z: Node[T], z: Node[T],
reversed: bool, reversed: bool,
rotating_around_root: bool,
rotate_left: RotateFunction[T], rotate_left: RotateFunction[T],
rotate_right: RotateFunction[T], rotate_right: RotateFunction[T],
) -> Optional[Node[T]]: ) -> None:
new_root = x new_root = x
v = y.left v = y.left
w = y.right w = y.right
@ -54,6 +55,8 @@ class WAVLTree(AVLTree[T]):
if w_diff == 1 and y.parent: if w_diff == 1 and y.parent:
logger.debug(f"y.parent = {y.parent}") logger.debug(f"y.parent = {y.parent}")
new_root = rotate_left(y.parent) new_root = rotate_left(y.parent)
if rotating_around_root:
self.root = new_root
y.promote() y.promote()
z.demote() z.demote()
@ -64,13 +67,13 @@ class WAVLTree(AVLTree[T]):
logger.debug(f"v.parent = {v.parent}") logger.debug(f"v.parent = {v.parent}")
rotate_right(v.parent) rotate_right(v.parent)
new_root = rotate_left(v.parent) new_root = rotate_left(v.parent)
if rotating_around_root:
self.root = new_root
v.promote().promote() v.promote().promote()
y.demote() y.demote()
z.demote().demote() z.demote().demote()
return new_root
def __bottomup_delete( def __bottomup_delete(
self, x: Optional[Node[T]], parent: Optional[Node[T]] self, x: Optional[Node[T]], parent: Optional[Node[T]]
) -> None: ) -> None:
@ -104,57 +107,54 @@ class WAVLTree(AVLTree[T]):
return return
rotating_around_root = parent.parent is None rotating_around_root = parent.parent is None
new_root: Optional[Node[T]] = parent
parent_node_diffs = Node.differences(parent) parent_node_diffs = Node.differences(parent)
if parent_node_diffs in ((1, 3), (3, 1)): if parent_node_diffs in ((1, 3), (3, 1)):
if parent.left is x: if parent.left is x:
assert parent.right assert parent.right
new_root = WAVLTree.__fix_delete( self.__fix_delete(
x, x,
parent.right, parent.right,
parent, parent,
False, False,
rotating_around_root,
Node.rotate_left, Node.rotate_left,
Node.rotate_right, Node.rotate_right,
) )
else: else:
assert parent.left assert parent.left
new_root = WAVLTree.__fix_delete( self.__fix_delete(
x, x,
parent.left, parent.left,
parent, parent,
True, True,
rotating_around_root,
Node.rotate_right, Node.rotate_right,
Node.rotate_left, Node.rotate_left,
) )
if rotating_around_root:
self.root = new_root
def __delete_fixup( def __delete_fixup(
self, y: Optional[Node[T]], parent: Optional[Node[T]] = None self, y: Optional[Node[T]], parent: Optional[Node[T]] = None
) -> None: ) -> None:
logger.debug(f"[__delete_fixup] y = {y}, parent = {parent}") logger.debug(f"[__delete_fixup] y = {y}, parent = {parent}")
z = y if y else parent if Node.differences(y) == (2, 2):
logger.debug( y.demote()
f"[z.demote()] Node.differences({repr(z)}) == (2, 2) ~>*" parent = y.parent
f"{Node.differences(z)} == (2, 2)" elif Node.differences(parent) == (2, 2):
) parent.demote()
assert z parent = parent.parent
# FIXME: In combination with propagation below, we get AVL tree
if Node.differences(z) == (2, 2):
z.demote()
if parent: if not parent:
for y in (parent.left, parent.right): return
logger.debug(
f"[bottom-up delete] Node.difference({y}, {parent}) == 3" for y in (parent.left, parent.right):
f"~>* {Node.difference(y, parent)} == 3" logger.debug(
) f"[bottom-up delete] Node.difference({y}, {parent}) == 3"
if Node.difference(y, parent) == 3: f"~>* {Node.difference(y, parent)} == 3"
self.__bottomup_delete(y, parent) )
if Node.difference(y, parent) == 3:
self.__bottomup_delete(y, parent)
def _delete_rebalance( def _delete_rebalance(
self, node: Optional[Node[T]], parent: Optional[Node[T]] self, node: Optional[Node[T]], parent: Optional[Node[T]]