Add homework for 2026.05.27
This commit is contained in:
@@ -1 +1,135 @@
|
|||||||
# Implement red-black rebalancing in code.
|
# Implement left rotates and right rotates for trees.
|
||||||
|
#
|
||||||
|
# Example right rotate on 10:
|
||||||
|
#
|
||||||
|
# 10
|
||||||
|
# / \
|
||||||
|
# 5 15
|
||||||
|
# / \
|
||||||
|
# 3 7
|
||||||
|
# /
|
||||||
|
# 2
|
||||||
|
#
|
||||||
|
# Turns into:
|
||||||
|
#
|
||||||
|
# 5
|
||||||
|
# / \
|
||||||
|
# 3 10
|
||||||
|
# / / \
|
||||||
|
# 2 7 15
|
||||||
|
#
|
||||||
|
# Notice how the right child of 10's left child (7) becomes the left child of 10.
|
||||||
|
#
|
||||||
|
# Left rotates are the reverse. See this example on 16:
|
||||||
|
# 16
|
||||||
|
# \
|
||||||
|
# 33
|
||||||
|
# / \
|
||||||
|
# 22 55
|
||||||
|
#
|
||||||
|
# Turns into:
|
||||||
|
#
|
||||||
|
# 33
|
||||||
|
# / \
|
||||||
|
# 16 55
|
||||||
|
# \
|
||||||
|
# 22
|
||||||
|
#
|
||||||
|
# where the left child of 16's right child (22) turns into 16's right child.
|
||||||
|
#
|
||||||
|
# Copy this entire file, implement rotate_left and rotate_right,
|
||||||
|
# and run the tests using `python3 <name-of-file>.py`.
|
||||||
|
|
||||||
|
|
||||||
|
class Node:
|
||||||
|
def __init__(self, value, left=None, right=None):
|
||||||
|
self.value = value
|
||||||
|
self.left: Node | None = left
|
||||||
|
self.right: Node | None = right
|
||||||
|
|
||||||
|
|
||||||
|
def rotate_left(node: Node) -> Node:
|
||||||
|
# TODO
|
||||||
|
return Node(0)
|
||||||
|
|
||||||
|
|
||||||
|
def rotate_right(node: Node) -> Node:
|
||||||
|
# TODO
|
||||||
|
return Node(0)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Tests ---------------------------------------------------------------
|
||||||
|
# Both rotate functions are expected to return the new root of the rotated
|
||||||
|
# subtree (the parent would then point its child link at that new root).
|
||||||
|
|
||||||
|
|
||||||
|
def to_tuple(node: Node | None):
|
||||||
|
"""Turn a tree into nested (value, left, right) tuples for easy comparison."""
|
||||||
|
if node is None:
|
||||||
|
return None
|
||||||
|
return (node.value, to_tuple(node.left), to_tuple(node.right))
|
||||||
|
|
||||||
|
|
||||||
|
def trees_equal(a: Node | None, b: Node | None) -> bool:
|
||||||
|
return to_tuple(a) == to_tuple(b)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
def test_rotate_right_example():
|
||||||
|
# The worksheet example: right rotate on 10.
|
||||||
|
root = Node(
|
||||||
|
10,
|
||||||
|
left=Node(5, left=Node(3, left=Node(2)), right=Node(7)),
|
||||||
|
right=Node(15),
|
||||||
|
)
|
||||||
|
expected = Node(
|
||||||
|
5,
|
||||||
|
left=Node(3, left=Node(2)),
|
||||||
|
right=Node(10, left=Node(7), right=Node(15)),
|
||||||
|
)
|
||||||
|
return rotate_right(root), expected
|
||||||
|
|
||||||
|
def test_rotate_left_example():
|
||||||
|
# The worksheet example: left rotate on 16.
|
||||||
|
root = Node(16, right=Node(33, left=Node(22), right=Node(55)))
|
||||||
|
expected = Node(33, left=Node(16, right=Node(22)), right=Node(55))
|
||||||
|
return rotate_left(root), expected
|
||||||
|
|
||||||
|
def test_rotate_right_two_nodes():
|
||||||
|
# Smallest case: a root with only a left child.
|
||||||
|
return rotate_right(Node(2, left=Node(1))), Node(1, right=Node(2))
|
||||||
|
|
||||||
|
def test_rotate_left_two_nodes():
|
||||||
|
# Smallest case: a root with only a right child.
|
||||||
|
return rotate_left(Node(1, right=Node(2))), Node(2, left=Node(1))
|
||||||
|
|
||||||
|
def test_round_trip():
|
||||||
|
# A left rotate undone by a right rotate restores the original tree.
|
||||||
|
original = Node(1, left=Node(0), right=Node(3, left=Node(2), right=Node(4)))
|
||||||
|
expected = Node(1, left=Node(0), right=Node(3, left=Node(2), right=Node(4)))
|
||||||
|
return rotate_right(rotate_left(original)), expected
|
||||||
|
|
||||||
|
tests = [
|
||||||
|
("rotate_right on worksheet example (10)", test_rotate_right_example),
|
||||||
|
("rotate_left on worksheet example (16)", test_rotate_left_example),
|
||||||
|
("rotate_right on two nodes", test_rotate_right_two_nodes),
|
||||||
|
("rotate_left on two nodes", test_rotate_left_two_nodes),
|
||||||
|
("rotate_left then rotate_right restores the tree", test_round_trip),
|
||||||
|
]
|
||||||
|
|
||||||
|
passed = 0
|
||||||
|
for name, test in tests:
|
||||||
|
try:
|
||||||
|
result, expected = test()
|
||||||
|
if trees_equal(result, expected):
|
||||||
|
print(f"PASS: {name}")
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
print(f"FAIL: {name}")
|
||||||
|
print(f" expected {to_tuple(expected)}")
|
||||||
|
print(f" got {to_tuple(result)}")
|
||||||
|
except Exception as e: # noqa: BLE001 - surface any bug as a failed test
|
||||||
|
print(f"ERROR: {name}: {type(e).__name__}: {e}")
|
||||||
|
|
||||||
|
print(f"\n{passed}/{len(tests)} tests passed")
|
||||||
|
|||||||
Reference in New Issue
Block a user