From 6efdc2e0c69d621edc42a4df13708ca4e0078810 Mon Sep 17 00:00:00 2001 From: lighting9999 Date: Sat, 5 Jul 2025 17:59:39 +0800 Subject: [PATCH 01/13] Delete data_structures/binary_tree/red_black_tree.py And then upload new py file is update this file. --- data_structures/binary_tree/red_black_tree.py | 716 ------------------ 1 file changed, 716 deletions(-) delete mode 100644 data_structures/binary_tree/red_black_tree.py diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py deleted file mode 100644 index 752db1e7026c..000000000000 --- a/data_structures/binary_tree/red_black_tree.py +++ /dev/null @@ -1,716 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator - - -class RedBlackTree: - """ - A Red-Black tree, which is a self-balancing BST (binary search - tree). - This tree has similar performance to AVL trees, but the balancing is - less strict, so it will perform faster for writing/deleting nodes - and slower for reading in the average case, though, because they're - both balanced binary search trees, both will get the same asymptotic - performance. - To read more about them, https://en.wikipedia.org/wiki/Red-black_tree - Unless otherwise specified, all asymptotic runtimes are specified in - terms of the size of the tree. - """ - - def __init__( - self, - label: int | None = None, - color: int = 0, - parent: RedBlackTree | None = None, - left: RedBlackTree | None = None, - right: RedBlackTree | None = None, - ) -> None: - """Initialize a new Red-Black Tree node with the given values: - label: The value associated with this node - color: 0 if black, 1 if red - parent: The parent to this node - left: This node's left child - right: This node's right child - """ - self.label = label - self.parent = parent - self.left = left - self.right = right - self.color = color - - # Here are functions which are specific to red-black trees - - def rotate_left(self) -> RedBlackTree: - """Rotate the subtree rooted at this node to the left and - returns the new root to this subtree. - Performing one rotation can be done in O(1). - """ - parent = self.parent - right = self.right - if right is None: - return self - self.right = right.left - if self.right: - self.right.parent = self - self.parent = right - right.left = self - if parent is not None: - if parent.left == self: - parent.left = right - else: - parent.right = right - right.parent = parent - return right - - def rotate_right(self) -> RedBlackTree: - """Rotate the subtree rooted at this node to the right and - returns the new root to this subtree. - Performing one rotation can be done in O(1). - """ - if self.left is None: - return self - parent = self.parent - left = self.left - self.left = left.right - if self.left: - self.left.parent = self - self.parent = left - left.right = self - if parent is not None: - if parent.right is self: - parent.right = left - else: - parent.left = left - left.parent = parent - return left - - def insert(self, label: int) -> RedBlackTree: - """Inserts label into the subtree rooted at self, performs any - rotations necessary to maintain balance, and then returns the - new root to this subtree (likely self). - This is guaranteed to run in O(log(n)) time. - """ - if self.label is None: - # Only possible with an empty tree - self.label = label - return self - if self.label == label: - return self - elif self.label > label: - if self.left: - self.left.insert(label) - else: - self.left = RedBlackTree(label, 1, self) - self.left._insert_repair() - elif self.right: - self.right.insert(label) - else: - self.right = RedBlackTree(label, 1, self) - self.right._insert_repair() - return self.parent or self - - def _insert_repair(self) -> None: - """Repair the coloring from inserting into a tree.""" - if self.parent is None: - # This node is the root, so it just needs to be black - self.color = 0 - elif color(self.parent) == 0: - # If the parent is black, then it just needs to be red - self.color = 1 - else: - uncle = self.parent.sibling - if color(uncle) == 0: - if self.is_left() and self.parent.is_right(): - self.parent.rotate_right() - if self.right: - self.right._insert_repair() - elif self.is_right() and self.parent.is_left(): - self.parent.rotate_left() - if self.left: - self.left._insert_repair() - elif self.is_left(): - if self.grandparent: - self.grandparent.rotate_right() - self.parent.color = 0 - if self.parent.right: - self.parent.right.color = 1 - else: - if self.grandparent: - self.grandparent.rotate_left() - self.parent.color = 0 - if self.parent.left: - self.parent.left.color = 1 - else: - self.parent.color = 0 - if uncle and self.grandparent: - uncle.color = 0 - self.grandparent.color = 1 - self.grandparent._insert_repair() - - def remove(self, label: int) -> RedBlackTree: - """Remove label from this tree.""" - if self.label == label: - if self.left and self.right: - # It's easier to balance a node with at most one child, - # so we replace this node with the greatest one less than - # it and remove that. - value = self.left.get_max() - if value is not None: - self.label = value - self.left.remove(value) - else: - # This node has at most one non-None child, so we don't - # need to replace - child = self.left or self.right - if self.color == 1: - # This node is red, and its child is black - # The only way this happens to a node with one child - # is if both children are None leaves. - # We can just remove this node and call it a day. - if self.parent: - if self.is_left(): - self.parent.left = None - else: - self.parent.right = None - # The node is black - elif child is None: - # This node and its child are black - if self.parent is None: - # The tree is now empty - return RedBlackTree(None) - else: - self._remove_repair() - if self.is_left(): - self.parent.left = None - else: - self.parent.right = None - self.parent = None - else: - # This node is black and its child is red - # Move the child node here and make it black - self.label = child.label - self.left = child.left - self.right = child.right - if self.left: - self.left.parent = self - if self.right: - self.right.parent = self - elif self.label is not None and self.label > label: - if self.left: - self.left.remove(label) - elif self.right: - self.right.remove(label) - return self.parent or self - - def _remove_repair(self) -> None: - """Repair the coloring of the tree that may have been messed up.""" - if ( - self.parent is None - or self.sibling is None - or self.parent.sibling is None - or self.grandparent is None - ): - return - if color(self.sibling) == 1: - self.sibling.color = 0 - self.parent.color = 1 - if self.is_left(): - self.parent.rotate_left() - else: - self.parent.rotate_right() - if ( - color(self.parent) == 0 - and color(self.sibling) == 0 - and color(self.sibling.left) == 0 - and color(self.sibling.right) == 0 - ): - self.sibling.color = 1 - self.parent._remove_repair() - return - if ( - color(self.parent) == 1 - and color(self.sibling) == 0 - and color(self.sibling.left) == 0 - and color(self.sibling.right) == 0 - ): - self.sibling.color = 1 - self.parent.color = 0 - return - if ( - self.is_left() - and color(self.sibling) == 0 - and color(self.sibling.right) == 0 - and color(self.sibling.left) == 1 - ): - self.sibling.rotate_right() - self.sibling.color = 0 - if self.sibling.right: - self.sibling.right.color = 1 - if ( - self.is_right() - and color(self.sibling) == 0 - and color(self.sibling.right) == 1 - and color(self.sibling.left) == 0 - ): - self.sibling.rotate_left() - self.sibling.color = 0 - if self.sibling.left: - self.sibling.left.color = 1 - if ( - self.is_left() - and color(self.sibling) == 0 - and color(self.sibling.right) == 1 - ): - self.parent.rotate_left() - self.grandparent.color = self.parent.color - self.parent.color = 0 - self.parent.sibling.color = 0 - if ( - self.is_right() - and color(self.sibling) == 0 - and color(self.sibling.left) == 1 - ): - self.parent.rotate_right() - self.grandparent.color = self.parent.color - self.parent.color = 0 - self.parent.sibling.color = 0 - - def check_color_properties(self) -> bool: - """Check the coloring of the tree, and return True iff the tree - is colored in a way which matches these five properties: - (wording stolen from wikipedia article) - 1. Each node is either red or black. - 2. The root node is black. - 3. All leaves are black. - 4. If a node is red, then both its children are black. - 5. Every path from any node to all of its descendent NIL nodes - has the same number of black nodes. - This function runs in O(n) time, because properties 4 and 5 take - that long to check. - """ - # I assume property 1 to hold because there is nothing that can - # make the color be anything other than 0 or 1. - # Property 2 - if self.color: - # The root was red - print("Property 2") - return False - # Property 3 does not need to be checked, because None is assumed - # to be black and is all the leaves. - # Property 4 - if not self.check_coloring(): - print("Property 4") - return False - # Property 5 - if self.black_height() is None: - print("Property 5") - return False - # All properties were met - return True - - def check_coloring(self) -> bool: - """A helper function to recursively check Property 4 of a - Red-Black Tree. See check_color_properties for more info. - """ - if self.color == 1 and 1 in (color(self.left), color(self.right)): - return False - if self.left and not self.left.check_coloring(): - return False - return not (self.right and not self.right.check_coloring()) - - def black_height(self) -> int | None: - """Returns the number of black nodes from this node to the - leaves of the tree, or None if there isn't one such value (the - tree is color incorrectly). - """ - if self is None or self.left is None or self.right is None: - # If we're already at a leaf, there is no path - return 1 - left = RedBlackTree.black_height(self.left) - right = RedBlackTree.black_height(self.right) - if left is None or right is None: - # There are issues with coloring below children nodes - return None - if left != right: - # The two children have unequal depths - return None - # Return the black depth of children, plus one if this node is - # black - return left + (1 - self.color) - - # Here are functions which are general to all binary search trees - - def __contains__(self, label: int) -> bool: - """Search through the tree for label, returning True iff it is - found somewhere in the tree. - Guaranteed to run in O(log(n)) time. - """ - return self.search(label) is not None - - def search(self, label: int) -> RedBlackTree | None: - """Search through the tree for label, returning its node if - it's found, and None otherwise. - This method is guaranteed to run in O(log(n)) time. - """ - if self.label == label: - return self - elif self.label is not None and label > self.label: - if self.right is None: - return None - else: - return self.right.search(label) - elif self.left is None: - return None - else: - return self.left.search(label) - - def floor(self, label: int) -> int | None: - """Returns the largest element in this tree which is at most label. - This method is guaranteed to run in O(log(n)) time.""" - if self.label == label: - return self.label - elif self.label is not None and self.label > label: - if self.left: - return self.left.floor(label) - else: - return None - else: - if self.right: - attempt = self.right.floor(label) - if attempt is not None: - return attempt - return self.label - - def ceil(self, label: int) -> int | None: - """Returns the smallest element in this tree which is at least label. - This method is guaranteed to run in O(log(n)) time. - """ - if self.label == label: - return self.label - elif self.label is not None and self.label < label: - if self.right: - return self.right.ceil(label) - else: - return None - else: - if self.left: - attempt = self.left.ceil(label) - if attempt is not None: - return attempt - return self.label - - def get_max(self) -> int | None: - """Returns the largest element in this tree. - This method is guaranteed to run in O(log(n)) time. - """ - if self.right: - # Go as far right as possible - return self.right.get_max() - else: - return self.label - - def get_min(self) -> int | None: - """Returns the smallest element in this tree. - This method is guaranteed to run in O(log(n)) time. - """ - if self.left: - # Go as far left as possible - return self.left.get_min() - else: - return self.label - - @property - def grandparent(self) -> RedBlackTree | None: - """Get the current node's grandparent, or None if it doesn't exist.""" - if self.parent is None: - return None - else: - return self.parent.parent - - @property - def sibling(self) -> RedBlackTree | None: - """Get the current node's sibling, or None if it doesn't exist.""" - if self.parent is None: - return None - elif self.parent.left is self: - return self.parent.right - else: - return self.parent.left - - def is_left(self) -> bool: - """Returns true iff this node is the left child of its parent.""" - if self.parent is None: - return False - return self.parent.left is self - - def is_right(self) -> bool: - """Returns true iff this node is the right child of its parent.""" - if self.parent is None: - return False - return self.parent.right is self - - def __bool__(self) -> bool: - return True - - def __len__(self) -> int: - """ - Return the number of nodes in this tree. - """ - ln = 1 - if self.left: - ln += len(self.left) - if self.right: - ln += len(self.right) - return ln - - def preorder_traverse(self) -> Iterator[int | None]: - yield self.label - if self.left: - yield from self.left.preorder_traverse() - if self.right: - yield from self.right.preorder_traverse() - - def inorder_traverse(self) -> Iterator[int | None]: - if self.left: - yield from self.left.inorder_traverse() - yield self.label - if self.right: - yield from self.right.inorder_traverse() - - def postorder_traverse(self) -> Iterator[int | None]: - if self.left: - yield from self.left.postorder_traverse() - if self.right: - yield from self.right.postorder_traverse() - yield self.label - - def __repr__(self) -> str: - from pprint import pformat - - if self.left is None and self.right is None: - return f"'{self.label} {(self.color and 'red') or 'blk'}'" - return pformat( - { - f"{self.label} {(self.color and 'red') or 'blk'}": ( - self.left, - self.right, - ) - }, - indent=1, - ) - - def __eq__(self, other: object) -> bool: - """Test if two trees are equal.""" - if not isinstance(other, RedBlackTree): - return NotImplemented - if self.label == other.label: - return self.left == other.left and self.right == other.right - else: - return False - - -def color(node: RedBlackTree | None) -> int: - """Returns the color of a node, allowing for None leaves.""" - if node is None: - return 0 - else: - return node.color - - -""" -Code for testing the various -functions of the red-black tree. -""" - - -def test_rotations() -> bool: - """Test that the rotate_left and rotate_right functions work.""" - # Make a tree to test on - tree = RedBlackTree(0) - tree.left = RedBlackTree(-10, parent=tree) - tree.right = RedBlackTree(10, parent=tree) - tree.left.left = RedBlackTree(-20, parent=tree.left) - tree.left.right = RedBlackTree(-5, parent=tree.left) - tree.right.left = RedBlackTree(5, parent=tree.right) - tree.right.right = RedBlackTree(20, parent=tree.right) - # Make the right rotation - left_rot = RedBlackTree(10) - left_rot.left = RedBlackTree(0, parent=left_rot) - left_rot.left.left = RedBlackTree(-10, parent=left_rot.left) - left_rot.left.right = RedBlackTree(5, parent=left_rot.left) - left_rot.left.left.left = RedBlackTree(-20, parent=left_rot.left.left) - left_rot.left.left.right = RedBlackTree(-5, parent=left_rot.left.left) - left_rot.right = RedBlackTree(20, parent=left_rot) - tree = tree.rotate_left() - if tree != left_rot: - return False - tree = tree.rotate_right() - tree = tree.rotate_right() - # Make the left rotation - right_rot = RedBlackTree(-10) - right_rot.left = RedBlackTree(-20, parent=right_rot) - right_rot.right = RedBlackTree(0, parent=right_rot) - right_rot.right.left = RedBlackTree(-5, parent=right_rot.right) - right_rot.right.right = RedBlackTree(10, parent=right_rot.right) - right_rot.right.right.left = RedBlackTree(5, parent=right_rot.right.right) - right_rot.right.right.right = RedBlackTree(20, parent=right_rot.right.right) - return tree == right_rot - - -def test_insertion_speed() -> bool: - """Test that the tree balances inserts to O(log(n)) by doing a lot - of them. - """ - tree = RedBlackTree(-1) - for i in range(300000): - tree = tree.insert(i) - return True - - -def test_insert() -> bool: - """Test the insert() method of the tree correctly balances, colors, - and inserts. - """ - tree = RedBlackTree(0) - tree.insert(8) - tree.insert(-8) - tree.insert(4) - tree.insert(12) - tree.insert(10) - tree.insert(11) - ans = RedBlackTree(0, 0) - ans.left = RedBlackTree(-8, 0, ans) - ans.right = RedBlackTree(8, 1, ans) - ans.right.left = RedBlackTree(4, 0, ans.right) - ans.right.right = RedBlackTree(11, 0, ans.right) - ans.right.right.left = RedBlackTree(10, 1, ans.right.right) - ans.right.right.right = RedBlackTree(12, 1, ans.right.right) - return tree == ans - - -def test_insert_and_search() -> bool: - """Tests searching through the tree for values.""" - tree = RedBlackTree(0) - tree.insert(8) - tree.insert(-8) - tree.insert(4) - tree.insert(12) - tree.insert(10) - tree.insert(11) - if any(i in tree for i in (5, -6, -10, 13)): - # Found something not in there - return False - # Find all these things in there - return all(i in tree for i in (11, 12, -8, 0)) - - -def test_insert_delete() -> bool: - """Test the insert() and delete() method of the tree, verifying the - insertion and removal of elements, and the balancing of the tree. - """ - tree = RedBlackTree(0) - tree = tree.insert(-12) - tree = tree.insert(8) - tree = tree.insert(-8) - tree = tree.insert(15) - tree = tree.insert(4) - tree = tree.insert(12) - tree = tree.insert(10) - tree = tree.insert(9) - tree = tree.insert(11) - tree = tree.remove(15) - tree = tree.remove(-12) - tree = tree.remove(9) - if not tree.check_color_properties(): - return False - return list(tree.inorder_traverse()) == [-8, 0, 4, 8, 10, 11, 12] - - -def test_floor_ceil() -> bool: - """Tests the floor and ceiling functions in the tree.""" - tree = RedBlackTree(0) - tree.insert(-16) - tree.insert(16) - tree.insert(8) - tree.insert(24) - tree.insert(20) - tree.insert(22) - tuples = [(-20, None, -16), (-10, -16, 0), (8, 8, 8), (50, 24, None)] - for val, floor, ceil in tuples: - if tree.floor(val) != floor or tree.ceil(val) != ceil: - return False - return True - - -def test_min_max() -> bool: - """Tests the min and max functions in the tree.""" - tree = RedBlackTree(0) - tree.insert(-16) - tree.insert(16) - tree.insert(8) - tree.insert(24) - tree.insert(20) - tree.insert(22) - return not (tree.get_max() != 22 or tree.get_min() != -16) - - -def test_tree_traversal() -> bool: - """Tests the three different tree traversal functions.""" - tree = RedBlackTree(0) - tree = tree.insert(-16) - tree.insert(16) - tree.insert(8) - tree.insert(24) - tree.insert(20) - tree.insert(22) - if list(tree.inorder_traverse()) != [-16, 0, 8, 16, 20, 22, 24]: - return False - if list(tree.preorder_traverse()) != [0, -16, 16, 8, 22, 20, 24]: - return False - return list(tree.postorder_traverse()) == [-16, 8, 20, 24, 22, 16, 0] - - -def test_tree_chaining() -> bool: - """Tests the three different tree chaining functions.""" - tree = RedBlackTree(0) - tree = tree.insert(-16).insert(16).insert(8).insert(24).insert(20).insert(22) - if list(tree.inorder_traverse()) != [-16, 0, 8, 16, 20, 22, 24]: - return False - if list(tree.preorder_traverse()) != [0, -16, 16, 8, 22, 20, 24]: - return False - return list(tree.postorder_traverse()) == [-16, 8, 20, 24, 22, 16, 0] - - -def print_results(msg: str, passes: bool) -> None: - print(str(msg), "works!" if passes else "doesn't work :(") - - -def pytests() -> None: - assert test_rotations() - assert test_insert() - assert test_insert_and_search() - assert test_insert_delete() - assert test_floor_ceil() - assert test_tree_traversal() - assert test_tree_chaining() - - -def main() -> None: - """ - >>> pytests() - """ - print_results("Rotating right and left", test_rotations()) - print_results("Inserting", test_insert()) - print_results("Searching", test_insert_and_search()) - print_results("Deleting", test_insert_delete()) - print_results("Floor and ceil", test_floor_ceil()) - print_results("Tree traversal", test_tree_traversal()) - print_results("Tree traversal", test_tree_chaining()) - print("Testing tree balancing...") - print("This should only be a few seconds.") - test_insertion_speed() - print("Done!") - - -if __name__ == "__main__": - main() From e8cdb245dc009bb6d98a9698fcecf3bade7d5f17 Mon Sep 17 00:00:00 2001 From: lighting9999 Date: Sat, 5 Jul 2025 18:02:42 +0800 Subject: [PATCH 02/13] Add files via upload --- data_structures/binary_tree/red_black_tree.py | 875 ++++++++++++++++++ 1 file changed, 875 insertions(+) create mode 100644 data_structures/binary_tree/red_black_tree.py diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py new file mode 100644 index 000000000000..1039be892e3a --- /dev/null +++ b/data_structures/binary_tree/red_black_tree.py @@ -0,0 +1,875 @@ +from __future__ import annotations + +import doctest +from collections.abc import Iterator +from pprint import pformat + + +class RedBlackTree: + """ + A Red-Black tree, which is a self-balancing BST (binary search + tree). + + Examples: + >>> tree = RedBlackTree(0) + >>> tree = tree.insert(8).insert(-8).insert(4).insert(12) + >>> tree.check_color_properties() + True + >>> list(tree.inorder_traverse()) + [-8, 0, 4, 8, 12] + >>> tree.search(4).label + 4 + >>> tree.floor(5) + 4 + >>> tree.ceil(5) + 8 + >>> tree.get_min() + -8 + >>> tree.get_max() + 12 + >>> tree = tree.remove(4) + >>> 4 in tree + False + """ + + def __init__( + self, + label: int | None = None, + color: int = 0, + parent: RedBlackTree | None = None, + left: RedBlackTree | None = None, + right: RedBlackTree | None = None, + ) -> None: + """Initialize a new Red-Black Tree node. + + Args: + label: The value associated with this node + color: 0 if black, 1 if red + parent: The parent to this node + left: This node's left child + right: This node's right child + + Examples: + >>> node = RedBlackTree(5) + >>> node.label + 5 + >>> node.color + 0 + """ + self.label = label + self.parent = parent + self.left = left + self.right = right + self.color = color + + def rotate_left(self) -> RedBlackTree: + """Rotate the subtree rooted at this node to the left. + + Returns: + The new root of the subtree + + Examples: + >>> root = RedBlackTree(2) + >>> root.right = RedBlackTree(4) + >>> root.right.left = RedBlackTree(3) + >>> new_root = root.rotate_left() + >>> new_root.label + 4 + >>> new_root.left.label + 2 + >>> new_root.left.right.label + 3 + """ + parent = self.parent + right = self.right + if right is None: + return self + self.right = right.left + if self.right: + self.right.parent = self + self.parent = right + right.left = self + if parent is not None: + if parent.left == self: + parent.left = right + else: + parent.right = right + right.parent = parent + return right + + def rotate_right(self) -> RedBlackTree: + """Rotate the subtree rooted at this node to the right. + + Returns: + The new root of the subtree + + Examples: + >>> root = RedBlackTree(4) + >>> root.left = RedBlackTree(2) + >>> root.left.right = RedBlackTree(3) + >>> new_root = root.rotate_right() + >>> new_root.label + 2 + >>> new_root.right.label + 4 + >>> new_root.right.left.label + 3 + """ + if self.left is None: + return self + parent = self.parent + left = self.left + self.left = left.right + if self.left: + self.left.parent = self + self.parent = left + left.right = self + if parent is not None: + if parent.right is self: + parent.right = left + else: + parent.left = left + left.parent = parent + return left + + def insert(self, label: int) -> RedBlackTree: + """Insert a label into the tree. + + Args: + label: The value to insert + + Returns: + The root of the tree + + Examples: + >>> tree = RedBlackTree() + >>> tree = tree.insert(5).insert(3).insert(7) + >>> list(tree.inorder_traverse()) + [3, 5, 7] + >>> tree.check_color_properties() + True + """ + if self.label is None: + self.label = label + return self + if self.label == label: + return self + elif self.label > label: + if self.left: + self.left.insert(label) + else: + self.left = RedBlackTree(label, 1, self) + self.left._insert_repair() + elif self.right: + self.right.insert(label) + else: + self.right = RedBlackTree(label, 1, self) + self.right._insert_repair() + return self.parent or self + + def _insert_repair(self) -> None: + """Repair the coloring after insertion.""" + if self.parent is None: + # This node is the root, so it just needs to be black + self.color = 0 + elif color(self.parent) == 0: + # If the parent is black, then it just needs to be red + self.color = 1 + else: + uncle = self.parent.sibling + if color(uncle) == 0: + if self.is_left() and self.parent.is_right(): + self.parent.rotate_right() + if self.right: + self.right._insert_repair() + elif self.is_right() and self.parent.is_left(): + self.parent.rotate_left() + if self.left: + self.left._insert_repair() + elif self.is_left(): + if self.grandparent: + self.grandparent.rotate_right() + self.parent.color = 0 + if self.parent.right: + self.parent.right.color = 1 + else: + if self.grandparent: + self.grandparent.rotate_left() + self.parent.color = 0 + if self.parent.left: + self.parent.left.color = 1 + else: + self.parent.color = 0 + if uncle and self.grandparent: + uncle.color = 0 + self.grandparent.color = 1 + self.grandparent._insert_repair() + + def remove(self, label: int) -> RedBlackTree: + """Remove a label from the tree. + + Args: + label: The value to remove + + Returns: + The root of the tree + + Examples: + >>> tree = RedBlackTree(5) + >>> tree = tree.insert(3).insert(7) + >>> tree = tree.remove(3) + >>> 3 in tree + False + >>> tree.check_color_properties() + True + """ + if self.label == label: + if self.left and self.right: + value = self.left.get_max() + if value is not None: + self.label = value + self.left.remove(value) + else: + child = self.left or self.right + if self.color == 1: + if self.parent: + if self.is_left(): + self.parent.left = None + else: + self.parent.right = None + elif child is None: + if self.parent is None: + return RedBlackTree(None) + else: + self._remove_repair() + if self.is_left(): + self.parent.left = None + else: + self.parent.right = None + self.parent = None + else: + self.label = child.label + self.left = child.left + self.right = child.right + if self.left: + self.left.parent = self + if self.right: + self.right.parent = self + elif self.label is not None and self.label > label: + if self.left: + self.left.remove(label) + elif self.right: + self.right.remove(label) + return self.parent or self + + def _remove_repair(self) -> None: + """Repair the coloring after removal.""" + if ( + self.parent is None + or self.sibling is None + or self.parent.sibling is None + or self.grandparent is None + ): + return + if color(self.sibling) == 1: + self.sibling.color = 0 + self.parent.color = 1 + if self.is_left(): + self.parent.rotate_left() + else: + self.parent.rotate_right() + if ( + color(self.parent) == 0 + and color(self.sibling) == 0 + and color(self.sibling.left) == 0 + and color(self.sibling.right) == 0 + ): + self.sibling.color = 1 + self.parent._remove_repair() + return + if ( + color(self.parent) == 1 + and color(self.sibling) == 0 + and color(self.sibling.left) == 0 + and color(self.sibling.right) == 0 + ): + self.sibling.color = 1 + self.parent.color = 0 + return + if ( + self.is_left() + and color(self.sibling) == 0 + and color(self.sibling.right) == 0 + and color(self.sibling.left) == 1 + ): + self.sibling.rotate_right() + self.sibling.color = 0 + if self.sibling.right: + self.sibling.right.color = 1 + if ( + self.is_right() + and color(self.sibling) == 0 + and color(self.sibling.right) == 1 + and color(self.sibling.left) == 0 + ): + self.sibling.rotate_left() + self.sibling.color = 0 + if self.sibling.left: + self.sibling.left.color = 1 + if ( + self.is_left() + and color(self.sibling) == 0 + and color(self.sibling.right) == 1 + ): + self.parent.rotate_left() + self.grandparent.color = self.parent.color + self.parent.color = 0 + self.parent.sibling.color = 0 + if ( + self.is_right() + and color(self.sibling) == 0 + and color(self.sibling.left) == 1 + ): + self.parent.rotate_right() + self.grandparent.color = self.parent.color + self.parent.color = 0 + self.parent.sibling.color = 0 + + def check_color_properties(self) -> bool: + """ + Verify that all Red-Black Tree properties are satisfied: + 1. Root node is black + 2. No two consecutive red nodes + 3. All paths have same black height + + Returns: + True if all properties are satisfied, False otherwise + """ + # Property 1: Root must be black + if self.parent is None and self.color != 0: + return False + + # Property 2: No two consecutive red nodes + if not self.check_coloring(): + return False + + # Property 3: All paths have same black height + return self.black_height() is not None + + def check_coloring(self) -> bool: + """Check if the tree satisfies Red-Black property 4.""" + if self.color == 1 and 1 in (color(self.left), color(self.right)): + return False + if self.left and not self.left.check_coloring(): + return False + return not (self.right and not self.right.check_coloring()) + + def black_height(self) -> int | None: + """ + Calculate the black height of the tree and verify consistency + - Black height = number of black nodes from current node to any leaf + - Returns None if any path has different black height + + Returns: + Black height if consistent, None otherwise + """ + # Leaf node case (both children are None) + if self.left is None and self.right is None: + # Count: current node (if black) + leaf (black) + return 1 + (1 - self.color) # 2 if black, 1 if red + + # Get black heights from both subtrees + left_bh = self.left.black_height() if self.left else 1 + right_bh = self.right.black_height() if self.right else 1 + + # Validate consistency + if left_bh is None or right_bh is None or left_bh != right_bh: + return None + + # Add current node's contribution (1 if black, 0 if red) + return left_bh + (1 - self.color) + + def __contains__(self, label: int) -> bool: + """Check if the tree contains a label. + + Args: + label: The value to check + + Returns: + True if the label is in the tree, False otherwise + + Examples: + >>> tree = RedBlackTree(5) + >>> tree = tree.insert(3) + >>> 3 in tree + True + >>> 4 in tree + False + """ + return self.search(label) is not None + + def search(self, label: int) -> RedBlackTree | None: + """Search for a label in the tree. + + Args: + label: The value to search for + + Returns: + The node containing the label, or None if not found + + Examples: + >>> tree = RedBlackTree(5) + >>> node = tree.search(5) + >>> node.label + 5 + >>> tree.search(10) is None + True + """ + if self.label == label: + return self + elif self.label is not None and label > self.label: + if self.right is None: + return None + else: + return self.right.search(label) + elif self.left is None: + return None + else: + return self.left.search(label) + + def floor(self, label: int) -> int | None: + """Find the largest element <= label. + + Args: + label: The value to find the floor of + + Returns: + The floor value, or None if no such element exists + + Examples: + >>> tree = RedBlackTree(5) + >>> tree = tree.insert(3).insert(7) + >>> tree.floor(6) + 5 + >>> tree.floor(2) is None + True + """ + if self.label == label: + return self.label + elif self.label is not None and self.label > label: + if self.left: + return self.left.floor(label) + else: + return None + else: + if self.right: + attempt = self.right.floor(label) + if attempt is not None: + return attempt + return self.label + + def ceil(self, label: int) -> int | None: + """Find the smallest element >= label. + + Args: + label: The value to find the ceil of + + Returns: + The ceil value, or None if no such element exists + + Examples: + >>> tree = RedBlackTree(5) + >>> tree = tree.insert(3).insert(7) + >>> tree.ceil(6) + 7 + >>> tree.ceil(8) is None + True + """ + if self.label == label: + return self.label + elif self.label is not None and self.label < label: + if self.right: + return self.right.ceil(label) + else: + return None + else: + if self.left: + attempt = self.left.ceil(label) + if attempt is not None: + return attempt + return self.label + + def get_max(self) -> int | None: + """Get the maximum element in the tree. + + Returns: + The maximum value, or None if the tree is empty + + Examples: + >>> tree = RedBlackTree(5) + >>> tree = tree.insert(3).insert(7) + >>> tree.get_max() + 7 + """ + if self.right: + return self.right.get_max() + else: + return self.label + + def get_min(self) -> int | None: + """Get the minimum element in the tree. + + Returns: + The minimum value, or None if the tree is empty + + Examples: + >>> tree = RedBlackTree(5) + >>> tree = tree.insert(3).insert(7) + >>> tree.get_min() + 3 + """ + if self.left: + return self.left.get_min() + else: + return self.label + + @property + def grandparent(self) -> RedBlackTree | None: + """Get the grandparent of this node.""" + if self.parent is None: + return None + else: + return self.parent.parent + + @property + def sibling(self) -> RedBlackTree | None: + """Get the sibling of this node.""" + if self.parent is None: + return None + elif self.parent.left is self: + return self.parent.right + else: + return self.parent.left + + def is_left(self) -> bool: + """Check if this node is the left child of its parent.""" + if self.parent is None: + return False + return self.parent.left is self + + def is_right(self) -> bool: + """Check if this node is the right child of its parent.""" + if self.parent is None: + return False + return self.parent.right is self + + def __bool__(self) -> bool: + """Return True if the tree is not empty.""" + return True + + def __len__(self) -> int: + """Return the number of nodes in the tree. + + Examples: + >>> tree = RedBlackTree(5) + >>> tree = tree.insert(3).insert(7) + >>> len(tree) + 3 + """ + ln = 1 + if self.left: + ln += len(self.left) + if self.right: + ln += len(self.right) + return ln + + def preorder_traverse(self) -> Iterator[int | None]: + """Traverse the tree in pre-order. + + Yields: + The values in pre-order + + Examples: + >>> tree = RedBlackTree(2) + >>> tree.left = RedBlackTree(1) + >>> tree.right = RedBlackTree(3) + >>> list(tree.preorder_traverse()) + [2, 1, 3] + """ + yield self.label + if self.left: + yield from self.left.preorder_traverse() + if self.right: + yield from self.right.preorder_traverse() + + def inorder_traverse(self) -> Iterator[int | None]: + """Traverse the tree in in-order. + + Yields: + The values in in-order + + Examples: + >>> tree = RedBlackTree(2) + >>> tree.left = RedBlackTree(1) + >>> tree.right = RedBlackTree(3) + >>> list(tree.inorder_traverse()) + [1, 2, 3] + """ + if self.left: + yield from self.left.inorder_traverse() + yield self.label + if self.right: + yield from self.right.inorder_traverse() + + def postorder_traverse(self) -> Iterator[int | None]: + """Traverse the tree in post-order. + + Yields: + The values in post-order + + Examples: + >>> tree = RedBlackTree(2) + >>> tree.left = RedBlackTree(1) + >>> tree.right = RedBlackTree(3) + >>> list(tree.postorder_traverse()) + [1, 3, 2] + """ + if self.left: + yield from self.left.postorder_traverse() + if self.right: + yield from self.right.postorder_traverse() + yield self.label + + def __repr__(self) -> str: + """Return a string representation of the tree.""" + if self.left is None and self.right is None: + return f"'{self.label} {(self.color and 'red') or 'blk'}'" + return pformat( + { + f"{self.label} {(self.color and 'red') or 'blk'}": ( + self.left, + self.right, + ) + }, + indent=1, + ) + + def __eq__(self, other: object) -> bool: + """Test if two trees are equal.""" + if not isinstance(other, RedBlackTree): + return NotImplemented + if self.label == other.label: + return self.left == other.left and self.right == other.right + else: + return False + + def __hash__(self): + """Return a hash value for the node.""" + return hash((self.label, self.color)) + + +def color(node: RedBlackTree | None) -> int: + """Returns the color of a node, allowing for None leaves.""" + if node is None: + return 0 + else: + return node.color + + +""" +Code for testing the various +functions of the red-black tree. +""" + + +def test_rotations() -> bool: + """Test that the rotate_left and rotate_right functions work.""" + tree = RedBlackTree(0) + tree.left = RedBlackTree(-10, parent=tree) + tree.right = RedBlackTree(10, parent=tree) + tree.left.left = RedBlackTree(-20, parent=tree.left) + tree.left.right = RedBlackTree(-5, parent=tree.left) + tree.right.left = RedBlackTree(5, parent=tree.right) + tree.right.right = RedBlackTree(20, parent=tree.right) + left_rot = RedBlackTree(10) + left_rot.left = RedBlackTree(0, parent=left_rot) + left_rot.left.left = RedBlackTree(-10, parent=left_rot.left) + left_rot.left.right = RedBlackTree(5, parent=left_rot.left) + left_rot.left.left.left = RedBlackTree(-20, parent=left_rot.left.left) + left_rot.left.left.right = RedBlackTree(-5, parent=left_rot.left.left) + left_rot.right = RedBlackTree(20, parent=left_rot) + tree = tree.rotate_left() + if tree != left_rot: + return False + tree = tree.rotate_right() + tree = tree.rotate_right() + right_rot = RedBlackTree(-10) + right_rot.left = RedBlackTree(-20, parent=right_rot) + right_rot.right = RedBlackTree(0, parent=right_rot) + right_rot.right.left = RedBlackTree(-5, parent=right_rot.right) + right_rot.right.right = RedBlackTree(10, parent=right_rot.right) + right_rot.right.right.left = RedBlackTree(5, parent=right_rot.right.right) + right_rot.right.right.right = RedBlackTree(20, parent=right_rot.right.right) + return tree == right_rot + + +def test_insertion_speed() -> bool: + """Test that the tree balances inserts to O(log(n)) by doing a lot + of them. + """ + tree = RedBlackTree(-1) + for i in range(300000): + tree = tree.insert(i) + return True + + +def test_insert() -> bool: + """Test the insert() method of the tree correctly balances, colors, + and inserts. + """ + tree = RedBlackTree(0) + tree.insert(8) + tree.insert(-8) + tree.insert(4) + tree.insert(12) + tree.insert(10) + tree.insert(11) + ans = RedBlackTree(0, 0) + ans.left = RedBlackTree(-8, 0, ans) + ans.right = RedBlackTree(8, 1, ans) + ans.right.left = RedBlackTree(4, 0, ans.right) + ans.right.right = RedBlackTree(11, 0, ans.right) + ans.right.right.left = RedBlackTree(10, 1, ans.right.right) + ans.right.right.right = RedBlackTree(12, 1, ans.right.right) + return tree == ans + + +def test_insert_and_search() -> bool: + """Tests searching through the tree for values.""" + tree = RedBlackTree(0) + tree.insert(8) + tree.insert(-8) + tree.insert(4) + tree.insert(12) + tree.insert(10) + tree.insert(11) + if any(i in tree for i in (5, -6, -10, 13)): + return False + return all(i in tree for i in (11, 12, -8, 0)) + + +def test_insert_delete() -> bool: + """Test the insert() and delete() method of the tree.""" + tree = RedBlackTree(0) + tree = tree.insert(-12) + tree = tree.insert(8) + tree = tree.insert(-8) + tree = tree.insert(15) + tree = tree.insert(4) + tree = tree.insert(12) + tree = tree.insert(10) + tree = tree.insert(9) + tree = tree.insert(11) + tree = tree.remove(15) + tree = tree.remove(-12) + tree = tree.remove(9) + if not tree.check_color_properties(): + return False + return list(tree.inorder_traverse()) == [-8, 0, 4, 8, 10, 11, 12] + + +def test_floor_ceil() -> bool: + """Tests the floor and ceiling functions in the tree.""" + tree = RedBlackTree(0) + tree.insert(-16) + tree.insert(16) + tree.insert(8) + tree.insert(24) + tree.insert(20) + tree.insert(22) + tuples = [(-20, None, -16), (-10, -16, 0), (8, 8, 8), (50, 24, None)] + for val, floor, ceil in tuples: + if tree.floor(val) != floor or tree.ceil(val) != ceil: + return False + return True + + +def test_min_max() -> bool: + """Tests the min and max functions in the tree.""" + tree = RedBlackTree(0) + tree.insert(-16) + tree.insert(16) + tree.insert(8) + tree.insert(24) + tree.insert(20) + tree.insert(22) + return not (tree.get_max() != 22 or tree.get_min() != -16) + + +def test_tree_traversal() -> bool: + """Tests the three different tree traversal functions.""" + tree = RedBlackTree(0) + tree = tree.insert(-16) + tree.insert(16) + tree.insert(8) + tree.insert(24) + tree.insert(20) + tree.insert(22) + if list(tree.inorder_traverse()) != [-16, 0, 8, 16, 20, 22, 24]: + return False + if list(tree.preorder_traverse()) != [0, -16, 16, 8, 22, 20, 24]: + return False + return list(tree.postorder_traverse()) == [-16, 8, 20, 24, 22, 16, 0] + + +def test_tree_chaining() -> bool: + """Tests the three different tree chaining functions.""" + tree = RedBlackTree(0) + tree = tree.insert(-16).insert(16).insert(8).insert(24).insert(20).insert(22) + if list(tree.inorder_traverse()) != [-16, 0, 8, 16, 20, 22, 24]: + return False + if list(tree.preorder_traverse()) != [0, -16, 16, 8, 22, 20, 24]: + return False + return list(tree.postorder_traverse()) == [-16, 8, 20, 24, 22, 16, 0] + + +def print_results(msg: str, passes: bool) -> None: + print(str(msg), "works!" if passes else "doesn't work :(") + + +def pytests() -> None: + assert test_rotations() + assert test_insert() + assert test_insert_and_search() + assert test_insert_delete() + assert test_floor_ceil() + assert test_tree_traversal() + assert test_tree_chaining() + + +def main() -> None: + """ + >>> pytests() + """ + + failures, _ = doctest.testmod() + if failures == 0: + print("All doctests passed!") + else: + print(f"{failures} doctests failed!") + + print_results("Rotating right and left", test_rotations()) + print_results("Inserting", test_insert()) + print_results("Searching", test_insert_and_search()) + print_results("Deleting", test_insert_delete()) + print_results("Floor and ceil", test_floor_ceil()) + print_results("Tree traversal", test_tree_traversal()) + print_results("Tree chaining", test_tree_chaining()) + print("Testing tree balancing...") + print("This should only be a few seconds.") + test_insertion_speed() + print("Done!") + + +if __name__ == "__main__": + main() From bdf2e8fb882bb8482e5a78de1da7f7531b054778 Mon Sep 17 00:00:00 2001 From: lighting9999 Date: Sat, 5 Jul 2025 18:06:00 +0800 Subject: [PATCH 03/13] Update red_black_tree.py --- data_structures/binary_tree/red_black_tree.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py index 1039be892e3a..698d2cb02c77 100644 --- a/data_structures/binary_tree/red_black_tree.py +++ b/data_structures/binary_tree/red_black_tree.py @@ -9,7 +9,14 @@ class RedBlackTree: """ A Red-Black tree, which is a self-balancing BST (binary search tree). - + This tree has similar performance to AVL trees, but the balancing is + less strict, so it will perform faster for writing/deleting nodes + and slower for reading in the average case, though, because they're + both balanced binary search trees, both will get the same asymptotic + performance. + To read more about them, https://en.wikipedia.org/wiki/Red-black_tree + Unless otherwise specified, all asymptotic runtimes are specified in + terms of the size of the tree. Examples: >>> tree = RedBlackTree(0) >>> tree = tree.insert(8).insert(-8).insert(4).insert(12) From f808b7e26ffae22131cb297e796ec7d32ea85a0c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 5 Jul 2025 10:06:24 +0000 Subject: [PATCH 04/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/binary_tree/red_black_tree.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py index 698d2cb02c77..926caf466963 100644 --- a/data_structures/binary_tree/red_black_tree.py +++ b/data_structures/binary_tree/red_black_tree.py @@ -9,13 +9,13 @@ class RedBlackTree: """ A Red-Black tree, which is a self-balancing BST (binary search tree). - This tree has similar performance to AVL trees, but the balancing is - less strict, so it will perform faster for writing/deleting nodes - and slower for reading in the average case, though, because they're - both balanced binary search trees, both will get the same asymptotic - performance. - To read more about them, https://en.wikipedia.org/wiki/Red-black_tree - Unless otherwise specified, all asymptotic runtimes are specified in + This tree has similar performance to AVL trees, but the balancing is + less strict, so it will perform faster for writing/deleting nodes + and slower for reading in the average case, though, because they're + both balanced binary search trees, both will get the same asymptotic + performance. + To read more about them, https://en.wikipedia.org/wiki/Red-black_tree + Unless otherwise specified, all asymptotic runtimes are specified in terms of the size of the tree. Examples: >>> tree = RedBlackTree(0) From 606d93c45830348127c2be5a7065ba46a9f0c570 Mon Sep 17 00:00:00 2001 From: lighting9999 Date: Sun, 6 Jul 2025 10:58:22 +0800 Subject: [PATCH 05/13] Update red_black_tree.py --- data_structures/binary_tree/red_black_tree.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py index 926caf466963..33cd60974df0 100644 --- a/data_structures/binary_tree/red_black_tree.py +++ b/data_structures/binary_tree/red_black_tree.py @@ -268,7 +268,9 @@ def remove(self, label: int) -> RedBlackTree: elif self.right: self.right.remove(label) return self.parent or self - + # It's easier to balance a node with at most one child, + # so we replace this node with the greatest one less than + # it and remove that. def _remove_repair(self) -> None: """Repair the coloring after removal.""" if ( From 108aa904e4e9260070397b65c2e90e7c4030fcdc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 6 Jul 2025 02:58:45 +0000 Subject: [PATCH 06/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/binary_tree/red_black_tree.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py index 33cd60974df0..5ca4e570aca6 100644 --- a/data_structures/binary_tree/red_black_tree.py +++ b/data_structures/binary_tree/red_black_tree.py @@ -268,9 +268,10 @@ def remove(self, label: int) -> RedBlackTree: elif self.right: self.right.remove(label) return self.parent or self - # It's easier to balance a node with at most one child, - # so we replace this node with the greatest one less than - # it and remove that. + # It's easier to balance a node with at most one child, + # so we replace this node with the greatest one less than + # it and remove that. + def _remove_repair(self) -> None: """Repair the coloring after removal.""" if ( From 13d22f2a6f62b1a767738541af8fa51c990063a8 Mon Sep 17 00:00:00 2001 From: lighting9999 Date: Sun, 6 Jul 2025 11:01:30 +0800 Subject: [PATCH 07/13] Update red_black_tree.py --- data_structures/binary_tree/red_black_tree.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py index 5ca4e570aca6..f673deae4461 100644 --- a/data_structures/binary_tree/red_black_tree.py +++ b/data_structures/binary_tree/red_black_tree.py @@ -231,7 +231,11 @@ def remove(self, label: int) -> RedBlackTree: True """ if self.label == label: - if self.left and self.right: + if self.left and self.right: +# It's easier to balance a node with at most one child, + # so we replace this node with the greatest one less than + # it and remove that. + value = self.left.get_max() if value is not None: self.label = value @@ -268,10 +272,7 @@ def remove(self, label: int) -> RedBlackTree: elif self.right: self.right.remove(label) return self.parent or self - # It's easier to balance a node with at most one child, - # so we replace this node with the greatest one less than - # it and remove that. - + def _remove_repair(self) -> None: """Repair the coloring after removal.""" if ( From 19e3f3c7b1b8e4c45a07c2a3581eed83420df562 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 6 Jul 2025 03:01:53 +0000 Subject: [PATCH 08/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/binary_tree/red_black_tree.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py index f673deae4461..9247c8492b8f 100644 --- a/data_structures/binary_tree/red_black_tree.py +++ b/data_structures/binary_tree/red_black_tree.py @@ -231,10 +231,10 @@ def remove(self, label: int) -> RedBlackTree: True """ if self.label == label: - if self.left and self.right: -# It's easier to balance a node with at most one child, - # so we replace this node with the greatest one less than - # it and remove that. + if self.left and self.right: + # It's easier to balance a node with at most one child, + # so we replace this node with the greatest one less than + # it and remove that. value = self.left.get_max() if value is not None: @@ -272,7 +272,7 @@ def remove(self, label: int) -> RedBlackTree: elif self.right: self.right.remove(label) return self.parent or self - + def _remove_repair(self) -> None: """Repair the coloring after removal.""" if ( From fbd72d9c848ddcf5375003652ea337ad58f0ebe9 Mon Sep 17 00:00:00 2001 From: lighting9999 Date: Sun, 6 Jul 2025 11:11:17 +0800 Subject: [PATCH 09/13] fix red_black_tree.py --- data_structures/binary_tree/red_black_tree.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py index 9247c8492b8f..be825c4ca278 100644 --- a/data_structures/binary_tree/red_black_tree.py +++ b/data_structures/binary_tree/red_black_tree.py @@ -1,6 +1,6 @@ from __future__ import annotations -import doctest + from collections.abc import Iterator from pprint import pformat @@ -862,7 +862,7 @@ def main() -> None: """ >>> pytests() """ - + import doctest failures, _ = doctest.testmod() if failures == 0: print("All doctests passed!") From 805fd98eee0c45bbc49876edcbbb155bbecc13d3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 6 Jul 2025 03:11:40 +0000 Subject: [PATCH 10/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/binary_tree/red_black_tree.py | 1 + 1 file changed, 1 insertion(+) diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py index be825c4ca278..619629726075 100644 --- a/data_structures/binary_tree/red_black_tree.py +++ b/data_structures/binary_tree/red_black_tree.py @@ -863,6 +863,7 @@ def main() -> None: >>> pytests() """ import doctest + failures, _ = doctest.testmod() if failures == 0: print("All doctests passed!") From 028cfa9ab42e3454e8b8478ca5c5f5b1e2eab219 Mon Sep 17 00:00:00 2001 From: lighting9999 Date: Sun, 6 Jul 2025 11:13:18 +0800 Subject: [PATCH 11/13] fix red_black_tree.py --- data_structures/binary_tree/red_black_tree.py | 1 - 1 file changed, 1 deletion(-) diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py index 619629726075..21048b7cdd4b 100644 --- a/data_structures/binary_tree/red_black_tree.py +++ b/data_structures/binary_tree/red_black_tree.py @@ -1,6 +1,5 @@ from __future__ import annotations - from collections.abc import Iterator from pprint import pformat From c161fee0e8a8a59608f4c0d6778af9f822ff24b7 Mon Sep 17 00:00:00 2001 From: lighting9999 Date: Sun, 6 Jul 2025 11:27:01 +0800 Subject: [PATCH 12/13] fix imports red_black_tree.py --- data_structures/binary_tree/red_black_tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py index 21048b7cdd4b..d25707db52b2 100644 --- a/data_structures/binary_tree/red_black_tree.py +++ b/data_structures/binary_tree/red_black_tree.py @@ -1,7 +1,6 @@ from __future__ import annotations from collections.abc import Iterator -from pprint import pformat class RedBlackTree: @@ -652,6 +651,7 @@ def postorder_traverse(self) -> Iterator[int | None]: def __repr__(self) -> str: """Return a string representation of the tree.""" + from pprint import pformat if self.left is None and self.right is None: return f"'{self.label} {(self.color and 'red') or 'blk'}'" return pformat( From 0c718d063e4110a540667091a6187b21a1e31846 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 6 Jul 2025 03:27:24 +0000 Subject: [PATCH 13/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- data_structures/binary_tree/red_black_tree.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data_structures/binary_tree/red_black_tree.py b/data_structures/binary_tree/red_black_tree.py index d25707db52b2..0e5c06d1c211 100644 --- a/data_structures/binary_tree/red_black_tree.py +++ b/data_structures/binary_tree/red_black_tree.py @@ -651,7 +651,8 @@ def postorder_traverse(self) -> Iterator[int | None]: def __repr__(self) -> str: """Return a string representation of the tree.""" - from pprint import pformat + from pprint import pformat + if self.left is None and self.right is None: return f"'{self.label} {(self.color and 'red') or 'blk'}'" return pformat(