From cef886c63c2619d60aae7036063175d08f8ed018 Mon Sep 17 00:00:00 2001 From: AVAniketh0905 Date: Tue, 3 Oct 2023 22:59:01 +0530 Subject: [PATCH 1/5] added serialize and desrialize bin tree --- .../serialize_deserialize_binary_tree.py | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 data_structures/binary_tree/serialize_deserialize_binary_tree.py diff --git a/data_structures/binary_tree/serialize_deserialize_binary_tree.py b/data_structures/binary_tree/serialize_deserialize_binary_tree.py new file mode 100644 index 000000000000..41c416df34b7 --- /dev/null +++ b/data_structures/binary_tree/serialize_deserialize_binary_tree.py @@ -0,0 +1,135 @@ +class TreeNode: + """ + A binary tree node has a value, left child, and right child. + + Props: + val(int): The value of the node. + left: The left child of the node. + right: The right child of the node. + """ + def __init__(self, val:int = 0, left = None, right = None) -> None: + if not isinstance(val, int): + raise TypeError("Value must be an integer.") + self.val = val + self.left = left + self.right = right + +# Helper functions +def are_trees_identical(root1: TreeNode, root2: TreeNode) -> bool: + """ + Check if two binary trees are identical. + + Args: + root1 (TreeNode): Tree 1 + root2 (TreeNode): Tree 2 + + Returns: + bool: True if the trees are identical, False otherwise. + + >>> root1 = TreeNode(1) + >>> root1.left = TreeNode(2) + >>> root1.right = TreeNode(3) + >>> root2 = TreeNode(1) + >>> root2.left = TreeNode(2) + >>> root2.right = TreeNode(3) + >>> are_trees_identical(root1, root2) + True + >>> root1 = TreeNode(1) + >>> root1.left = TreeNode(2) + >>> root1.right = TreeNode(3) + >>> root2 = TreeNode(1) + >>> root2.left = TreeNode(2) + >>> root2.right = TreeNode(4) + >>> are_trees_identical(root1, root2) + False + """ + + if not root1 and not root2: + return True + if not root1 or not root2: + return False + + return ( + root1.val == root2.val + and are_trees_identical(root1.left, root2.left) + and are_trees_identical(root1.right, root2.right) + ) + +# Main functions +def serialize(root: TreeNode) -> str: + """ + Serialize a binary tree to a string using preorder traversal. + + Args: + root(TreeNode): The root of the binary tree. + + Returns: + A string representation of the binary tree. + + >>> root = TreeNode(1) + >>> root.left = TreeNode(2) + >>> root.right = TreeNode(3) + >>> root.right.left = TreeNode(4) + >>> root.right.right = TreeNode(5) + >>> serialize(root) + '1,2,null,null,3,4,null,null,5,null,null' + >>> root = TreeNode(1) + >>> serialize(root) + '1,null,null' + """ + + # Use "null" to represent empty nodes in the serialization + if not root: + return "null" + + return str(root.val) + "," + serialize(root.left) + "," + serialize(root.right) + +def deserialize(data: str) -> TreeNode: + """ + Deserialize a string to a binary tree. + + Args: + data(str): The serialized string. + + Returns: + The root of the binary tree. + + >>> root = TreeNode(1) + >>> root.left = TreeNode(2) + >>> root.right = TreeNode(3) + >>> root.right.left = TreeNode(4) + >>> root.right.right = TreeNode(5) + >>> serialzed_data = serialize(root) + >>> deserialized = deserialize(serialzed_data) + >>> are_trees_identical(root, deserialized) + True + >>> root = TreeNode(1) + >>> serialzed_data = serialize(root) + >>> dummy_data = "1,2,null,null,3,4,null,null,5,null,null" + >>> deserialized = deserialize(dummy_data) + >>> are_trees_identical(root, deserialized) + False + """ + + # Split the serialized string by comma to get node values + nodes = data.split(",") + + def build_tree(): + # Get the next value from the list + val = nodes.pop(0) + + if val == "null": + return None + + node = TreeNode(int(val)) + node.left = build_tree() # Recursively build left subtree + node.right = build_tree() # Recursively build right subtree + + return node + + return build_tree() + +if __name__ == "__main__": + import doctest + + doctest.testmod() \ No newline at end of file From 5923c9290dc765458cd698a20ca72e8e3c80645d Mon Sep 17 00:00:00 2001 From: AVAniketh0905 Date: Tue, 3 Oct 2023 23:03:02 +0530 Subject: [PATCH 2/5] format files --- .../serialize_deserialize_binary_tree.py | 59 ++++++++++--------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/data_structures/binary_tree/serialize_deserialize_binary_tree.py b/data_structures/binary_tree/serialize_deserialize_binary_tree.py index 41c416df34b7..e092ecf2c0d0 100644 --- a/data_structures/binary_tree/serialize_deserialize_binary_tree.py +++ b/data_structures/binary_tree/serialize_deserialize_binary_tree.py @@ -1,31 +1,33 @@ class TreeNode: """ A binary tree node has a value, left child, and right child. - + Props: val(int): The value of the node. left: The left child of the node. right: The right child of the node. """ - def __init__(self, val:int = 0, left = None, right = None) -> None: + + def __init__(self, val: int = 0, left=None, right=None) -> None: if not isinstance(val, int): raise TypeError("Value must be an integer.") self.val = val self.left = left self.right = right + # Helper functions def are_trees_identical(root1: TreeNode, root2: TreeNode) -> bool: """ Check if two binary trees are identical. - + Args: root1 (TreeNode): Tree 1 root2 (TreeNode): Tree 2 Returns: bool: True if the trees are identical, False otherwise. - + >>> root1 = TreeNode(1) >>> root1.left = TreeNode(2) >>> root1.right = TreeNode(3) @@ -43,29 +45,30 @@ def are_trees_identical(root1: TreeNode, root2: TreeNode) -> bool: >>> are_trees_identical(root1, root2) False """ - + if not root1 and not root2: return True if not root1 or not root2: return False - + return ( root1.val == root2.val and are_trees_identical(root1.left, root2.left) and are_trees_identical(root1.right, root2.right) ) + # Main functions def serialize(root: TreeNode) -> str: """ Serialize a binary tree to a string using preorder traversal. - + Args: root(TreeNode): The root of the binary tree. - + Returns: A string representation of the binary tree. - + >>> root = TreeNode(1) >>> root.left = TreeNode(2) >>> root.right = TreeNode(3) @@ -77,23 +80,24 @@ def serialize(root: TreeNode) -> str: >>> serialize(root) '1,null,null' """ - + # Use "null" to represent empty nodes in the serialization if not root: - return "null" - + return "null" + return str(root.val) + "," + serialize(root.left) + "," + serialize(root.right) + def deserialize(data: str) -> TreeNode: """ Deserialize a string to a binary tree. - - Args: + + Args: data(str): The serialized string. - + Returns: The root of the binary tree. - + >>> root = TreeNode(1) >>> root.left = TreeNode(2) >>> root.right = TreeNode(3) @@ -110,26 +114,27 @@ def deserialize(data: str) -> TreeNode: >>> are_trees_identical(root, deserialized) False """ - + # Split the serialized string by comma to get node values - nodes = data.split(",") - + nodes = data.split(",") + def build_tree(): # Get the next value from the list - val = nodes.pop(0) - + val = nodes.pop(0) + if val == "null": return None - + node = TreeNode(int(val)) - node.left = build_tree() # Recursively build left subtree - node.right = build_tree() # Recursively build right subtree - + node.left = build_tree() # Recursively build left subtree + node.right = build_tree() # Recursively build right subtree + return node return build_tree() - + + if __name__ == "__main__": import doctest - doctest.testmod() \ No newline at end of file + doctest.testmod() From 2e10621c1cfb6bee804eb21b95d52f6c4c519213 Mon Sep 17 00:00:00 2001 From: AVAniketh0905 Date: Tue, 3 Oct 2023 23:10:56 +0530 Subject: [PATCH 3/5] added type hints --- .../binary_tree/serialize_deserialize_binary_tree.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/data_structures/binary_tree/serialize_deserialize_binary_tree.py b/data_structures/binary_tree/serialize_deserialize_binary_tree.py index e092ecf2c0d0..85ee4b333f99 100644 --- a/data_structures/binary_tree/serialize_deserialize_binary_tree.py +++ b/data_structures/binary_tree/serialize_deserialize_binary_tree.py @@ -1,3 +1,5 @@ +from __future__ import annotations + class TreeNode: """ A binary tree node has a value, left child, and right child. @@ -8,7 +10,7 @@ class TreeNode: right: The right child of the node. """ - def __init__(self, val: int = 0, left=None, right=None) -> None: + def __init__(self, val: int = 0, left:TreeNode = None, right:TreeNode = None) -> None: if not isinstance(val, int): raise TypeError("Value must be an integer.") self.val = val @@ -118,7 +120,7 @@ def deserialize(data: str) -> TreeNode: # Split the serialized string by comma to get node values nodes = data.split(",") - def build_tree(): + def build_tree() -> TreeNode: # Get the next value from the list val = nodes.pop(0) From 44ec94dafbe85279638f3e76fd9626c3b9d04f4a Mon Sep 17 00:00:00 2001 From: AVAniketh0905 Date: Tue, 3 Oct 2023 23:19:48 +0530 Subject: [PATCH 4/5] added type hints --- .../serialize_deserialize_binary_tree.py | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/data_structures/binary_tree/serialize_deserialize_binary_tree.py b/data_structures/binary_tree/serialize_deserialize_binary_tree.py index 85ee4b333f99..309979ef524a 100644 --- a/data_structures/binary_tree/serialize_deserialize_binary_tree.py +++ b/data_structures/binary_tree/serialize_deserialize_binary_tree.py @@ -1,5 +1,6 @@ from __future__ import annotations + class TreeNode: """ A binary tree node has a value, left child, and right child. @@ -10,7 +11,12 @@ class TreeNode: right: The right child of the node. """ - def __init__(self, val: int = 0, left:TreeNode = None, right:TreeNode = None) -> None: + def __init__( + self, + val: int = 0, + left: TreeNode | None = None, + right: TreeNode | None = None, + ) -> None: if not isinstance(val, int): raise TypeError("Value must be an integer.") self.val = val @@ -19,7 +25,7 @@ def __init__(self, val: int = 0, left:TreeNode = None, right:TreeNode = None) -> # Helper functions -def are_trees_identical(root1: TreeNode, root2: TreeNode) -> bool: +def are_trees_identical(root1: TreeNode | None, root2: TreeNode | None) -> bool: """ Check if two binary trees are identical. @@ -61,7 +67,7 @@ def are_trees_identical(root1: TreeNode, root2: TreeNode) -> bool: # Main functions -def serialize(root: TreeNode) -> str: +def serialize(root: TreeNode | None) -> str: """ Serialize a binary tree to a string using preorder traversal. @@ -90,7 +96,7 @@ def serialize(root: TreeNode) -> str: return str(root.val) + "," + serialize(root.left) + "," + serialize(root.right) -def deserialize(data: str) -> TreeNode: +def deserialize(data: str) -> TreeNode | None: """ Deserialize a string to a binary tree. @@ -115,12 +121,19 @@ def deserialize(data: str) -> TreeNode: >>> deserialized = deserialize(dummy_data) >>> are_trees_identical(root, deserialized) False + >>> deserialize("") + Traceback (most recent call last): + ... + ValueError: Data cannot be empty. """ + if data == "": + raise ValueError("Data cannot be empty.") + # Split the serialized string by comma to get node values nodes = data.split(",") - def build_tree() -> TreeNode: + def build_tree() -> TreeNode | None: # Get the next value from the list val = nodes.pop(0) From 7cc2602e8bfc0503c92a9bb3106204e95c4a5d3a Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sun, 29 Oct 2023 23:59:02 +0100 Subject: [PATCH 5/5] Use dataclass .__eq__(), .__iter__(), and .__repr__() --- .../serialize_deserialize_binary_tree.py | 185 ++++++++---------- 1 file changed, 85 insertions(+), 100 deletions(-) diff --git a/data_structures/binary_tree/serialize_deserialize_binary_tree.py b/data_structures/binary_tree/serialize_deserialize_binary_tree.py index 309979ef524a..7d3e0c61f96d 100644 --- a/data_structures/binary_tree/serialize_deserialize_binary_tree.py +++ b/data_structures/binary_tree/serialize_deserialize_binary_tree.py @@ -1,99 +1,86 @@ from __future__ import annotations +from collections.abc import Iterator +from dataclasses import dataclass + +@dataclass class TreeNode: """ A binary tree node has a value, left child, and right child. Props: - val(int): The value of the node. + value: The value of the node. left: The left child of the node. right: The right child of the node. """ - def __init__( - self, - val: int = 0, - left: TreeNode | None = None, - right: TreeNode | None = None, - ) -> None: - if not isinstance(val, int): - raise TypeError("Value must be an integer.") - self.val = val - self.left = left - self.right = right - - -# Helper functions -def are_trees_identical(root1: TreeNode | None, root2: TreeNode | None) -> bool: - """ - Check if two binary trees are identical. - - Args: - root1 (TreeNode): Tree 1 - root2 (TreeNode): Tree 2 - - Returns: - bool: True if the trees are identical, False otherwise. - - >>> root1 = TreeNode(1) - >>> root1.left = TreeNode(2) - >>> root1.right = TreeNode(3) - >>> root2 = TreeNode(1) - >>> root2.left = TreeNode(2) - >>> root2.right = TreeNode(3) - >>> are_trees_identical(root1, root2) - True - >>> root1 = TreeNode(1) - >>> root1.left = TreeNode(2) - >>> root1.right = TreeNode(3) - >>> root2 = TreeNode(1) - >>> root2.left = TreeNode(2) - >>> root2.right = TreeNode(4) - >>> are_trees_identical(root1, root2) - False - """ - - if not root1 and not root2: - return True - if not root1 or not root2: - return False - - return ( - root1.val == root2.val - and are_trees_identical(root1.left, root2.left) - and are_trees_identical(root1.right, root2.right) - ) + value: int = 0 + left: TreeNode | None = None + right: TreeNode | None = None + def __post_init__(self): + if not isinstance(self.value, int): + raise TypeError("Value must be an integer.") -# Main functions -def serialize(root: TreeNode | None) -> str: - """ - Serialize a binary tree to a string using preorder traversal. - - Args: - root(TreeNode): The root of the binary tree. - - Returns: - A string representation of the binary tree. - - >>> root = TreeNode(1) - >>> root.left = TreeNode(2) - >>> root.right = TreeNode(3) - >>> root.right.left = TreeNode(4) - >>> root.right.right = TreeNode(5) - >>> serialize(root) - '1,2,null,null,3,4,null,null,5,null,null' - >>> root = TreeNode(1) - >>> serialize(root) - '1,null,null' - """ - - # Use "null" to represent empty nodes in the serialization - if not root: - return "null" - - return str(root.val) + "," + serialize(root.left) + "," + serialize(root.right) + def __iter__(self) -> Iterator[TreeNode]: + """ + Iterate through the tree in preorder. + + Returns: + An iterator of the tree nodes. + + >>> list(TreeNode(1)) + [1,null,null] + >>> tuple(TreeNode(1, TreeNode(2), TreeNode(3))) + (1,2,null,null,3,null,null, 2,null,null, 3,null,null) + """ + yield self + yield from self.left or () + yield from self.right or () + + def __len__(self) -> int: + """ + Count the number of nodes in the tree. + + Returns: + The number of nodes in the tree. + + >>> len(TreeNode(1)) + 1 + >>> len(TreeNode(1, TreeNode(2), TreeNode(3))) + 3 + """ + return sum(1 for _ in self) + + def __repr__(self) -> str: + """ + Represent the tree as a string. + + Returns: + A string representation of the tree. + + >>> repr(TreeNode(1)) + '1,null,null' + >>> repr(TreeNode(1, TreeNode(2), TreeNode(3))) + '1,2,null,null,3,null,null' + >>> repr(TreeNode(1, TreeNode(2), TreeNode(3, TreeNode(4), TreeNode(5)))) + '1,2,null,null,3,4,null,null,5,null,null' + """ + return f"{self.value},{self.left!r},{self.right!r}".replace("None", "null") + + @classmethod + def five_tree(cls) -> TreeNode: + """ + >>> repr(TreeNode.five_tree()) + '1,2,null,null,3,4,null,null,5,null,null' + """ + root = TreeNode(1) + root.left = TreeNode(2) + root.right = TreeNode(3) + root.right.left = TreeNode(4) + root.right.right = TreeNode(5) + return root def deserialize(data: str) -> TreeNode | None: @@ -106,44 +93,42 @@ def deserialize(data: str) -> TreeNode | None: Returns: The root of the binary tree. - >>> root = TreeNode(1) - >>> root.left = TreeNode(2) - >>> root.right = TreeNode(3) - >>> root.right.left = TreeNode(4) - >>> root.right.right = TreeNode(5) - >>> serialzed_data = serialize(root) + >>> root = TreeNode.five_tree() + >>> serialzed_data = repr(root) >>> deserialized = deserialize(serialzed_data) - >>> are_trees_identical(root, deserialized) + >>> root == deserialized True - >>> root = TreeNode(1) - >>> serialzed_data = serialize(root) - >>> dummy_data = "1,2,null,null,3,4,null,null,5,null,null" - >>> deserialized = deserialize(dummy_data) - >>> are_trees_identical(root, deserialized) + >>> root is deserialized # two separate trees + False + >>> root.right.right.value = 6 + >>> root == deserialized False + >>> serialzed_data = repr(root) + >>> deserialized = deserialize(serialzed_data) + >>> root == deserialized + True >>> deserialize("") Traceback (most recent call last): ... ValueError: Data cannot be empty. """ - if data == "": + if not data: raise ValueError("Data cannot be empty.") - # Split the serialized string by comma to get node values + # Split the serialized string by a comma to get node values nodes = data.split(",") def build_tree() -> TreeNode | None: # Get the next value from the list - val = nodes.pop(0) + value = nodes.pop(0) - if val == "null": + if value == "null": return None - node = TreeNode(int(val)) + node = TreeNode(int(value)) node.left = build_tree() # Recursively build left subtree node.right = build_tree() # Recursively build right subtree - return node return build_tree()