mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-27 15:01:08 +00:00
serialize deserialize binary tree (#9625)
* added serialize and desrialize bin tree * format files * added type hints * added type hints * Use dataclass .__eq__(), .__iter__(), and .__repr__() --------- Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
parent
2531f8e221
commit
c38b222212
140
data_structures/binary_tree/serialize_deserialize_binary_tree.py
Normal file
140
data_structures/binary_tree/serialize_deserialize_binary_tree.py
Normal file
|
@ -0,0 +1,140 @@
|
|||
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:
|
||||
value: The value of the node.
|
||||
left: The left child of the node.
|
||||
right: The right child of the node.
|
||||
"""
|
||||
|
||||
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.")
|
||||
|
||||
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:
|
||||
"""
|
||||
Deserialize a string to a binary tree.
|
||||
|
||||
Args:
|
||||
data(str): The serialized string.
|
||||
|
||||
Returns:
|
||||
The root of the binary tree.
|
||||
|
||||
>>> root = TreeNode.five_tree()
|
||||
>>> serialzed_data = repr(root)
|
||||
>>> deserialized = deserialize(serialzed_data)
|
||||
>>> root == deserialized
|
||||
True
|
||||
>>> 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 not data:
|
||||
raise ValueError("Data cannot be empty.")
|
||||
|
||||
# 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
|
||||
value = nodes.pop(0)
|
||||
|
||||
if value == "null":
|
||||
return None
|
||||
|
||||
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()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
Loading…
Reference in New Issue
Block a user