Skip to content

Commit 15d069e

Browse files
committed
refactor(datastructures, trees): cleanup typing
1 parent f02e2cf commit 15d069e

11 files changed

Lines changed: 314 additions & 264 deletions

File tree

datastructures/trees/__init__.py

Lines changed: 3 additions & 236 deletions
Original file line numberDiff line numberDiff line change
@@ -1,237 +1,4 @@
1-
from typing import List, Generic, TypeVar, Any
2-
from abc import ABC, abstractmethod
3-
from .node import TreeNode
1+
from datastructures.trees.tree import Tree, TreeNode, T
2+
from datastructures.trees.binary import BinaryTree, BinaryTreeNode
43

5-
T = TypeVar("T", bound=Any)
6-
7-
8-
class Tree(ABC, Generic[T]):
9-
"""
10-
Tree abstract base class that defines common methods & properties of a typical Tree data structure
11-
"""
12-
13-
@abstractmethod
14-
def __len__(self) -> int:
15-
"""
16-
Calculates the number of nodes in the Tree
17-
:returns: number of nodes in the tree
18-
"""
19-
raise NotImplementedError("This method has not been implemented")
20-
21-
@abstractmethod
22-
def next(self) -> int:
23-
raise NotImplementedError("This method has not been implemented")
24-
25-
@abstractmethod
26-
def height(self) -> int:
27-
"""
28-
Returns the height of the Tree. That is, the number of edges between the root node and the furthest leaf node.
29-
This can also be the maximum depth of the Tree
30-
This is the number of links from the root to the furthest leaf.
31-
"""
32-
raise NotImplementedError("This method has not been implemented")
33-
34-
@abstractmethod
35-
def lowest_common_ancestor(
36-
self, node_one: TreeNode, node_two: TreeNode
37-
) -> TreeNode:
38-
"""
39-
Returns the lowest common ancestor of 2 nodes in the Tree.
40-
:param node_one
41-
:param node_two
42-
:returns the lowest common ancestor of the Tree
43-
:rtype TreeNode
44-
"""
45-
raise NotImplementedError("This method has not been implemented")
46-
47-
@abstractmethod
48-
def has_next(self) -> bool:
49-
raise NotImplementedError("This method has not been implemented")
50-
51-
@abstractmethod
52-
def increasing_order_traversal(self) -> TreeNode:
53-
"""
54-
Rearranges the tree in in-order so that the leftmost node in the tree is now the root of the tree
55-
and every node has no left child and only one right child
56-
:returns root of tree of new tree
57-
"""
58-
raise NotImplementedError("This method has not been implemented")
59-
60-
@abstractmethod
61-
def get_depth(self) -> int:
62-
"""
63-
Gets the depth of the tree or height of the tree
64-
:returns height/depth of the tree
65-
"""
66-
raise NotImplementedError("This method has not been implemented")
67-
68-
@abstractmethod
69-
def insert_node(self, value) -> TreeNode:
70-
"""
71-
Based on the type of tree, this inserts a node in the Tree
72-
"""
73-
raise NotImplementedError("This method has not been implemented")
74-
75-
@abstractmethod
76-
def paths(self) -> list:
77-
"""
78-
Prints all the paths of a Tree from root node to leaf nodes
79-
"""
80-
raise NotImplementedError("This method has not been implemented")
81-
82-
@abstractmethod
83-
def level_order_traversal(self) -> List[T]:
84-
raise NotImplementedError("This method has not been implemented")
85-
86-
def reverse_level_order_traversal(self) -> List[T]:
87-
"""
88-
Performs a level order traversal on the tree in reverse order where the leaf nodes are first iterated through
89-
and then the internal nodes before the root node is added to the collection
90-
91-
Complexity:
92-
Where `n` is the number of nodes in the tree
93-
94-
Time Complexity: O(n) as each node in the tree is traversed
95-
Space Complexity: O(n) as each node or node data is stored in a list/collection to be returned
96-
97-
Returns:
98-
List: list of nodes or node values/data traversed in a reverse level order fashion.
99-
"""
100-
raise NotImplementedError("This method has not been implemented")
101-
102-
@abstractmethod
103-
def pre_order_traversal(self) -> List[T]:
104-
"""Traverses the tree in pre-order walking the left subtree before finally walking the right subtree returning
105-
a list of values on each node
106-
107-
Complexity:
108-
Time Complexity O(n): where n is the number of nodes in the tree, as the algorithm has to traverse all the nodes
109-
in the tree
110-
111-
Space Complexity O(h), where h is the height of the tree
112-
113-
Returns:
114-
list: list of values of each node
115-
"""
116-
raise NotImplementedError("This method has not been implemented")
117-
118-
def inorder_traversal(self) -> List[T]:
119-
"""
120-
Walks the left subtree first, then visits the current node, and finally walks the right subtree
121-
The algorithm looks something like this:
122-
123-
1. Check if the current node is empty/null.
124-
2. Traverse the left subtree by recursively calling the in-order method.
125-
3. Display the data part of the root (or current node).
126-
4. Traverse the right subtree by recursively calling the in-order method.
127-
128-
Complexity:
129-
Where `n` is the number of nodes in the tree
130-
131-
Time Complexity: O(n) as each node in the tree is traversed
132-
Space Complexity: O(n) as each node or node data is stored in a list/collection to be returned
133-
134-
Returns:
135-
List: list of nodes or node values/data traversed in inorder traversal fashion.
136-
"""
137-
138-
def post_order_traversal(self) -> List[T]:
139-
"""
140-
Walks the left subtree first, then the right subtree and finally visits the current node
141-
The algorithm looks something like this:
142-
143-
1. Check if the current node is empty/null.
144-
2. Traverse the left subtree by recursively calling the post-order method.
145-
3. Traverse the right subtree by recursively calling the post-order method.
146-
4. Display the data part of the root (or current node).
147-
148-
Complexity:
149-
Where `n` is the number of nodes in the tree
150-
151-
Time Complexity: O(n) as each node in the tree is traversed
152-
Space Complexity: O(n) as each node or node data is stored in a list/collection to be returned
153-
154-
Returns:
155-
List: list of nodes or node values/data traversed in inorder traversal fashion.
156-
"""
157-
158-
@abstractmethod
159-
def is_balanced(self) -> bool:
160-
"""
161-
Checks if this tree is balanced.
162-
A balanced tree is a tree where every node has 0 or more n children for n-ary trees or for binary trees, where
163-
the heights of its left and right subtrees differ by at most 1 or 0 and both subtrees are also balanced.
164-
@return: True if the tree is balanced, false otherwise
165-
"""
166-
raise NotImplementedError("This method has not yet been implemented")
167-
168-
@abstractmethod
169-
def leaf_similar(self, other: "Tree") -> bool:
170-
"""
171-
Returns true if this tree has similar leaf value sequence to another tree.
172-
For example: If this tree has nodes = [3,5,1,6,2,9,8,null,null,7,4] and other tree has nodes =
173-
[3,5,1,6,7,4,2,null,null,null,null,null,null,9,8]. Then the leaf value sequence of both is [6,7,4,9,8] which is
174-
similar
175-
@param other: Other tree
176-
@return: True if the sequence of both tree's leaves is similar, false otherwise
177-
"""
178-
raise NotImplementedError("not yet implemented")
179-
180-
@abstractmethod
181-
def number_of_good_nodes(self) -> int:
182-
"""
183-
Finds the number of good nodes in a tree. A good node is a node in which in the path from root to the node there
184-
are no nodes with a value greater than it
185-
@return: The number of good nodes
186-
"""
187-
raise NotImplementedError("not yet implemented")
188-
189-
@abstractmethod
190-
def path_sum(self, target: T) -> int:
191-
"""Returns the number of paths where the sum of the values along the path equals target
192-
193-
Args:
194-
target (T): The target that the sum of values along the path must equal
195-
196-
Returns:
197-
int: The number of paths along which the values equal the target
198-
"""
199-
raise NotImplementedError("not yet implemented")
200-
201-
@abstractmethod
202-
def paths_to_target(self, target: T) -> List[T]:
203-
"""Returns the paths where the sum of the values along the path equals to the given target
204-
205-
Args:
206-
target (T): The target that the sum of values along the path must equal
207-
208-
Returns:
209-
list: The paths along which the values equal the target
210-
"""
211-
raise NotImplementedError("not yet implemented")
212-
213-
def max_level_sum(self) -> int:
214-
"""Returns the smallest level x such that the sum of all the values of nodes at level x is maximal
215-
216-
Returns:
217-
int: maximum value at level x
218-
"""
219-
raise NotImplementedError("not yet implemented")
220-
221-
@abstractmethod
222-
def serialize(self) -> str:
223-
"""Serializes a tree into a string
224-
Returns:
225-
str: string representation of tree.
226-
"""
227-
raise NotImplementedError("not yet implemented")
228-
229-
@staticmethod
230-
def deserialize(tree_str: str) -> "Tree":
231-
"""Serializes a tree into a string
232-
Args:
233-
tree_str (str): string representation of tree
234-
Returns:
235-
Tree: Tree deserialized from string
236-
"""
237-
raise NotImplementedError("not yet implemented")
4+
__all__ = ["Tree", "TreeNode", "BinaryTree", "BinaryTreeNode"]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from datastructures.trees.binary.tree import (
2+
BinaryTree,
3+
create_tree_from_nodes,
4+
level_order_traversal,
5+
longest_uni_value_path,
6+
)
7+
from datastructures.trees.binary.node import BinaryTreeNode
8+
from datastructures.trees.binary.utils import (
9+
lowest_common_ancestor,
10+
lowest_common_ancestor_ptr,
11+
connect_all_siblings,
12+
connect_all_siblings_ptr,
13+
mirror_binary_tree,
14+
)
15+
16+
__all__ = [
17+
"BinaryTree",
18+
"BinaryTreeNode",
19+
"create_tree_from_nodes",
20+
"level_order_traversal",
21+
"longest_uni_value_path",
22+
"lowest_common_ancestor",
23+
"lowest_common_ancestor_ptr",
24+
"connect_all_siblings",
25+
"connect_all_siblings_ptr",
26+
"mirror_binary_tree",
27+
]

datastructures/trees/binary/search_tree/avl/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from typing import Optional, List
2-
from datastructures.trees import Tree, T
2+
from datastructures.trees.tree import Tree, T
33
from .node import AvlTreeNode
44

55

datastructures/trees/binary/search_tree/binary_search_tree.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ def increasing_order_traversal(self) -> Optional[BinaryTreeNode]:
456456
if not self.root:
457457
return None
458458

459-
def inorder(node: BinaryTreeNode):
459+
def inorder(node: Optional[BinaryTreeNode]):
460460
if node:
461461
yield from inorder(node.left)
462462
yield node.data
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
from datastructures.trees.binary.tree.binary_tree import BinaryTree
2+
from datastructures.trees.binary.tree.binary_tree_utils import (
3+
create_tree_from_nodes,
4+
level_order_traversal,
5+
longest_uni_value_path,
6+
)
27

3-
__all__ = ["BinaryTree"]
8+
__all__ = [
9+
"BinaryTree",
10+
"create_tree_from_nodes",
11+
"level_order_traversal",
12+
"longest_uni_value_path",
13+
]

datastructures/trees/binary/tree/binary_tree.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
from itertools import chain
55

66
from datastructures.stacks.dynamic import DynamicSizeStack
7-
from datastructures.trees import Tree, TreeNode, T
7+
from datastructures.trees.tree import Tree, T
8+
from datastructures.trees.node import TreeNode
89
from datastructures.trees.binary.node import BinaryTreeNode
910
from datastructures.trees.binary.tree.binary_tree_utils import longest_uni_value_path
1011
from datastructures.queues.fifo import FifoQueue
@@ -159,7 +160,7 @@ def pre_order_traversal(self) -> List[Any]:
159160
if not self.root:
160161
return data
161162

162-
def pre_order_helper(root: BinaryTreeNode):
163+
def pre_order_helper(root: Optional[BinaryTreeNode]):
163164
if not root:
164165
return
165166
data.append(root.data)
@@ -174,7 +175,7 @@ def inorder_traversal(self) -> List[T]:
174175
if not self.root:
175176
return data
176177

177-
def inorder_helper(root: BinaryTreeNode):
178+
def inorder_helper(root: Optional[BinaryTreeNode]):
178179
if not root:
179180
return
180181
inorder_helper(root.left)
@@ -189,7 +190,7 @@ def post_order_traversal(self) -> List[T]:
189190
if not self.root:
190191
return data
191192

192-
def post_order_helper(root: BinaryTreeNode):
193+
def post_order_helper(root: Optional[BinaryTreeNode]):
193194
if not root:
194195
return
195196
post_order_helper(root.left)

datastructures/trees/binary/tree/test_binary_tree.py

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -729,25 +729,6 @@ def test_1(self):
729729
self.assertListEqual(expected, actual)
730730

731731

732-
class BinaryTreeInOrderTraversal(unittest.TestCase):
733-
def test_1(self):
734-
"""Should return [A, B, C, D, E, F, G, H, I]"""
735-
expected = ["A", "B", "C", "D", "E", "F", "G", "H", "I"]
736-
right = BinaryTreeNode("G", right=BinaryTreeNode("I", left=BinaryTreeNode("H")))
737-
left = BinaryTreeNode(
738-
"B",
739-
left=BinaryTreeNode("A"),
740-
right=BinaryTreeNode(
741-
"D", left=BinaryTreeNode("C"), right=BinaryTreeNode("E")
742-
),
743-
)
744-
root = BinaryTreeNode("F", left=left, right=right)
745-
746-
tree = BinaryTree(root=root)
747-
actual = tree.inorder_traversal()
748-
self.assertListEqual(expected, actual)
749-
750-
751732
class BinaryTreePostOrderTraversal(unittest.TestCase):
752733
def test_1(self):
753734
"""Should return [A, C, E, D, B, H, I, G, F]"""
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import unittest
2+
3+
from datastructures.trees.binary.tree import BinaryTree
4+
from datastructures.trees.binary.node import BinaryTreeNode
5+
6+
7+
class BinaryTreeInOrderTraversal(unittest.TestCase):
8+
def test_1(self):
9+
"""Should return [A, B, C, D, E, F, G, H, I]"""
10+
expected = ["A", "B", "C", "D", "E", "F", "G", "H", "I"]
11+
right = BinaryTreeNode("G", right=BinaryTreeNode("I", left=BinaryTreeNode("H")))
12+
left = BinaryTreeNode(
13+
"B",
14+
left=BinaryTreeNode("A"),
15+
right=BinaryTreeNode(
16+
"D", left=BinaryTreeNode("C"), right=BinaryTreeNode("E")
17+
),
18+
)
19+
root = BinaryTreeNode("F", left=left, right=right)
20+
21+
tree = BinaryTree(root=root)
22+
actual = tree.inorder_traversal()
23+
self.assertListEqual(expected, actual)
24+
25+
26+
if __name__ == "__main__":
27+
unittest.main()

datastructures/trees/nary/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import List, Any
22
from collections import deque
3-
from .. import Tree, T
3+
from datastructures.trees.tree import Tree, T
44
from .node import NAryNode
55

66

0 commit comments

Comments
 (0)