Skip to content

Commit 24a2b88

Browse files
AVAniketh0905cclauss
authored andcommitted
serialize deserialize binary tree (TheAlgorithms#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 <[email protected]>
1 parent f2514ed commit 24a2b88

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
from __future__ import annotations
2+
3+
from collections.abc import Iterator
4+
from dataclasses import dataclass
5+
6+
7+
@dataclass
8+
class TreeNode:
9+
"""
10+
A binary tree node has a value, left child, and right child.
11+
12+
Props:
13+
value: The value of the node.
14+
left: The left child of the node.
15+
right: The right child of the node.
16+
"""
17+
18+
value: int = 0
19+
left: TreeNode | None = None
20+
right: TreeNode | None = None
21+
22+
def __post_init__(self):
23+
if not isinstance(self.value, int):
24+
raise TypeError("Value must be an integer.")
25+
26+
def __iter__(self) -> Iterator[TreeNode]:
27+
"""
28+
Iterate through the tree in preorder.
29+
30+
Returns:
31+
An iterator of the tree nodes.
32+
33+
>>> list(TreeNode(1))
34+
[1,null,null]
35+
>>> tuple(TreeNode(1, TreeNode(2), TreeNode(3)))
36+
(1,2,null,null,3,null,null, 2,null,null, 3,null,null)
37+
"""
38+
yield self
39+
yield from self.left or ()
40+
yield from self.right or ()
41+
42+
def __len__(self) -> int:
43+
"""
44+
Count the number of nodes in the tree.
45+
46+
Returns:
47+
The number of nodes in the tree.
48+
49+
>>> len(TreeNode(1))
50+
1
51+
>>> len(TreeNode(1, TreeNode(2), TreeNode(3)))
52+
3
53+
"""
54+
return sum(1 for _ in self)
55+
56+
def __repr__(self) -> str:
57+
"""
58+
Represent the tree as a string.
59+
60+
Returns:
61+
A string representation of the tree.
62+
63+
>>> repr(TreeNode(1))
64+
'1,null,null'
65+
>>> repr(TreeNode(1, TreeNode(2), TreeNode(3)))
66+
'1,2,null,null,3,null,null'
67+
>>> repr(TreeNode(1, TreeNode(2), TreeNode(3, TreeNode(4), TreeNode(5))))
68+
'1,2,null,null,3,4,null,null,5,null,null'
69+
"""
70+
return f"{self.value},{self.left!r},{self.right!r}".replace("None", "null")
71+
72+
@classmethod
73+
def five_tree(cls) -> TreeNode:
74+
"""
75+
>>> repr(TreeNode.five_tree())
76+
'1,2,null,null,3,4,null,null,5,null,null'
77+
"""
78+
root = TreeNode(1)
79+
root.left = TreeNode(2)
80+
root.right = TreeNode(3)
81+
root.right.left = TreeNode(4)
82+
root.right.right = TreeNode(5)
83+
return root
84+
85+
86+
def deserialize(data: str) -> TreeNode | None:
87+
"""
88+
Deserialize a string to a binary tree.
89+
90+
Args:
91+
data(str): The serialized string.
92+
93+
Returns:
94+
The root of the binary tree.
95+
96+
>>> root = TreeNode.five_tree()
97+
>>> serialzed_data = repr(root)
98+
>>> deserialized = deserialize(serialzed_data)
99+
>>> root == deserialized
100+
True
101+
>>> root is deserialized # two separate trees
102+
False
103+
>>> root.right.right.value = 6
104+
>>> root == deserialized
105+
False
106+
>>> serialzed_data = repr(root)
107+
>>> deserialized = deserialize(serialzed_data)
108+
>>> root == deserialized
109+
True
110+
>>> deserialize("")
111+
Traceback (most recent call last):
112+
...
113+
ValueError: Data cannot be empty.
114+
"""
115+
116+
if not data:
117+
raise ValueError("Data cannot be empty.")
118+
119+
# Split the serialized string by a comma to get node values
120+
nodes = data.split(",")
121+
122+
def build_tree() -> TreeNode | None:
123+
# Get the next value from the list
124+
value = nodes.pop(0)
125+
126+
if value == "null":
127+
return None
128+
129+
node = TreeNode(int(value))
130+
node.left = build_tree() # Recursively build left subtree
131+
node.right = build_tree() # Recursively build right subtree
132+
return node
133+
134+
return build_tree()
135+
136+
137+
if __name__ == "__main__":
138+
import doctest
139+
140+
doctest.testmod()

0 commit comments

Comments
 (0)