stepps 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {stepps-0.2.0 → stepps-0.3.0}/PKG-INFO +1 -1
- {stepps-0.2.0 → stepps-0.3.0}/pyproject.toml +1 -1
- stepps-0.3.0/src/stepps/tree_builder/__init__.py +21 -0
- stepps-0.3.0/src/stepps/tree_builder/inorder_tree_builder.py +10 -0
- {stepps-0.2.0/src/stepps/TreeBuilder → stepps-0.3.0/src/stepps/tree_builder}/inorder_tree_builder_impl.py +1 -1
- stepps-0.3.0/src/stepps/tree_builder/level_order_tree_builder.py +10 -0
- {stepps-0.2.0/src/stepps/TreeBuilder → stepps-0.3.0/src/stepps/tree_builder}/level_order_tree_builder_impl.py +1 -1
- stepps-0.3.0/src/stepps/tree_builder/postorder_tree_builder.py +10 -0
- {stepps-0.2.0/src/stepps/TreeBuilder → stepps-0.3.0/src/stepps/tree_builder}/postorder_tree_builder_impl.py +1 -1
- stepps-0.3.0/src/stepps/tree_builder/preorder_tree_builder.py +10 -0
- {stepps-0.2.0/src/stepps/TreeBuilder → stepps-0.3.0/src/stepps/tree_builder}/preorder_tree_builder_impl.py +1 -1
- {stepps-0.2.0/src/stepps/TreeBuilder → stepps-0.3.0/src/stepps/tree_builder}/tree_builder.py +3 -2
- stepps-0.3.0/src/stepps/trees/balanced/__init__.py +4 -0
- stepps-0.3.0/src/stepps/trees/balanced/avl.py +19 -0
- stepps-0.3.0/src/stepps/trees/balanced/avl_impl.py +245 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/trees/binary_tree.py +26 -5
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/trees/binary_tree_impl.py +24 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/trees/bst.py +1 -1
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/trees/tree.py +3 -2
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/visualizer/cli_visualizer.py +2 -1
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/visualizer/tree_visualizer.py +3 -2
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps.egg-info/PKG-INFO +1 -1
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps.egg-info/SOURCES.txt +14 -10
- stepps-0.3.0/tests/test_avl.py +368 -0
- {stepps-0.2.0 → stepps-0.3.0}/tests/test_binary_tree.py +75 -0
- {stepps-0.2.0 → stepps-0.3.0}/tests/test_inorder_tree_builder.py +1 -1
- {stepps-0.2.0 → stepps-0.3.0}/tests/test_level_order_tree_builder.py +1 -1
- {stepps-0.2.0 → stepps-0.3.0}/tests/test_postorder_tree_builder.py +1 -1
- {stepps-0.2.0 → stepps-0.3.0}/tests/test_preorder_tree_builder.py +1 -1
- stepps-0.2.0/src/stepps/TreeBuilder/__init__.py +0 -13
- stepps-0.2.0/src/stepps/TreeBuilder/inorder_tree_builder.py +0 -8
- stepps-0.2.0/src/stepps/TreeBuilder/level_order_tree_builder.py +0 -8
- stepps-0.2.0/src/stepps/TreeBuilder/postorder_tree_builder.py +0 -8
- stepps-0.2.0/src/stepps/TreeBuilder/preorder_tree_builder.py +0 -8
- {stepps-0.2.0 → stepps-0.3.0}/LICENSE +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/README.md +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/setup.cfg +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/__init__.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/iterators/__init__.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/iterators/base_iterator.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/iterators/inorder.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/iterators/levelorder.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/iterators/postorder.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/iterators/preorder.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/nodes/__init__.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/nodes/binary_node.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/py.typed +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/trees/__init__.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/trees/bst_impl.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/visualizer/__init__.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps/visualizer/cli_visualizer_impl.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps.egg-info/dependency_links.txt +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/src/stepps.egg-info/top_level.txt +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/tests/test_bst.py +0 -0
- {stepps-0.2.0 → stepps-0.3.0}/tests/test_visualizer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stepps
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Useful algorithms in Python
|
|
5
5
|
Author-email: Suhas Krishna Srivastava <suhas.srivastava@vaastav.tech>, Trinay Mitra <trinay.mitra@vaastav.tech>
|
|
6
6
|
Maintainer-email: Suhas Krishna Srivastava <suhas.srivastava@vaastav.tech>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from stepps.tree_builder.inorder_tree_builder import InOrderTreeBuilder
|
|
2
|
+
from stepps.tree_builder.inorder_tree_builder_impl import InOrderTreeBuilderImpl
|
|
3
|
+
from stepps.tree_builder.level_order_tree_builder import LevelOrderTreeBuilder
|
|
4
|
+
from stepps.tree_builder.level_order_tree_builder_impl import LevelOrderTreeBuilderImpl
|
|
5
|
+
from stepps.tree_builder.postorder_tree_builder import PostOrderTreeBuilder
|
|
6
|
+
from stepps.tree_builder.postorder_tree_builder_impl import PostOrderTreeBuilderImpl
|
|
7
|
+
from stepps.tree_builder.preorder_tree_builder import PreOrderTreeBuilder
|
|
8
|
+
from stepps.tree_builder.preorder_tree_builder_impl import PreOrderTreeBuilderImpl
|
|
9
|
+
from stepps.tree_builder.tree_builder import TreeBuilder
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"InOrderTreeBuilder",
|
|
13
|
+
"InOrderTreeBuilderImpl",
|
|
14
|
+
"LevelOrderTreeBuilder",
|
|
15
|
+
"LevelOrderTreeBuilderImpl",
|
|
16
|
+
"PostOrderTreeBuilder",
|
|
17
|
+
"PostOrderTreeBuilderImpl",
|
|
18
|
+
"PreOrderTreeBuilder",
|
|
19
|
+
"PreOrderTreeBuilderImpl",
|
|
20
|
+
"TreeBuilder",
|
|
21
|
+
]
|
|
@@ -2,7 +2,7 @@ from collections.abc import Sequence
|
|
|
2
2
|
from typing import override
|
|
3
3
|
|
|
4
4
|
from stepps.nodes import BinaryNode
|
|
5
|
-
from stepps.
|
|
5
|
+
from stepps.tree_builder.inorder_tree_builder import InOrderTreeBuilder
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class InOrderTreeBuilderImpl[T](InOrderTreeBuilder[T]):
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from typing import Protocol
|
|
2
|
+
|
|
3
|
+
from stepps.tree_builder.tree_builder import TreeBuilder
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LevelOrderTreeBuilder[T](TreeBuilder[T], Protocol):
|
|
7
|
+
"""
|
|
8
|
+
Define the interface for building a binary tree from a sequence
|
|
9
|
+
using level-order traversal.
|
|
10
|
+
"""
|
|
@@ -3,7 +3,7 @@ from collections.abc import Sequence
|
|
|
3
3
|
from typing import override
|
|
4
4
|
|
|
5
5
|
from stepps.nodes import BinaryNode
|
|
6
|
-
from stepps.
|
|
6
|
+
from stepps.tree_builder.level_order_tree_builder import LevelOrderTreeBuilder
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class LevelOrderTreeBuilderImpl[T](LevelOrderTreeBuilder[T]):
|
|
@@ -2,7 +2,7 @@ from collections.abc import Sequence
|
|
|
2
2
|
from typing import override
|
|
3
3
|
|
|
4
4
|
from stepps.nodes import BinaryNode
|
|
5
|
-
from stepps.
|
|
5
|
+
from stepps.tree_builder.postorder_tree_builder import PostOrderTreeBuilder
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class PostOrderTreeBuilderImpl[T](PostOrderTreeBuilder[T]):
|
|
@@ -2,7 +2,7 @@ from collections.abc import Sequence
|
|
|
2
2
|
from typing import override
|
|
3
3
|
|
|
4
4
|
from stepps.nodes import BinaryNode
|
|
5
|
-
from stepps.
|
|
5
|
+
from stepps.tree_builder.preorder_tree_builder import PreOrderTreeBuilder
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class PreOrderTreeBuilderImpl[T](PreOrderTreeBuilder[T]):
|
{stepps-0.2.0/src/stepps/TreeBuilder → stepps-0.3.0/src/stepps/tree_builder}/tree_builder.py
RENAMED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
from abc import
|
|
1
|
+
from abc import abstractmethod
|
|
2
2
|
from collections.abc import Sequence
|
|
3
|
+
from typing import Protocol
|
|
3
4
|
|
|
4
5
|
from stepps.nodes import BinaryNode
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
class TreeBuilder[T](
|
|
8
|
+
class TreeBuilder[T](Protocol):
|
|
8
9
|
"""
|
|
9
10
|
Define the interface for building a binary tree from a sequence.
|
|
10
11
|
"""
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import Protocol
|
|
3
|
+
|
|
4
|
+
from stepps.trees.binary_tree import BinaryTree
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AVL[T](BinaryTree[T], Protocol):
|
|
8
|
+
"""
|
|
9
|
+
Define the interface for balancing a binary tree.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def balance(self) -> BinaryTree[T]:
|
|
14
|
+
"""
|
|
15
|
+
Balance the binary tree.
|
|
16
|
+
|
|
17
|
+
:return: The balanced binary tree.
|
|
18
|
+
"""
|
|
19
|
+
...
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
from typing import override
|
|
2
|
+
|
|
3
|
+
from stepps.nodes import BinaryNode
|
|
4
|
+
from stepps.trees.balanced.avl import AVL
|
|
5
|
+
from stepps.trees.binary_tree import BinaryTree
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AVLImpl[T](AVL[T]):
|
|
9
|
+
"""
|
|
10
|
+
Provide the default implementation for balancing a binary tree using AVL
|
|
11
|
+
rotations.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
tree: BinaryTree[T],
|
|
17
|
+
balance_factor: int = 1,
|
|
18
|
+
) -> None:
|
|
19
|
+
self.tree = tree
|
|
20
|
+
self.balance_factor = balance_factor
|
|
21
|
+
|
|
22
|
+
@override
|
|
23
|
+
def balance(self) -> BinaryTree[T]:
|
|
24
|
+
"""
|
|
25
|
+
Balance the tree using AVL rotations.
|
|
26
|
+
|
|
27
|
+
:return: The balanced tree.
|
|
28
|
+
"""
|
|
29
|
+
self.tree = self._balance(self.tree)
|
|
30
|
+
return self.tree
|
|
31
|
+
|
|
32
|
+
def insert(self, value: T) -> BinaryNode[T]:
|
|
33
|
+
"""
|
|
34
|
+
Insert a value into the tree and balance it.
|
|
35
|
+
|
|
36
|
+
:param value: The value to insert.
|
|
37
|
+
:return: The inserted node.
|
|
38
|
+
"""
|
|
39
|
+
node = self.tree.insert(value)
|
|
40
|
+
self.balance()
|
|
41
|
+
return node
|
|
42
|
+
|
|
43
|
+
def delete(self, value: T) -> bool:
|
|
44
|
+
"""
|
|
45
|
+
Delete a value from the tree and balance it.
|
|
46
|
+
|
|
47
|
+
:param value: The value to delete.
|
|
48
|
+
:return: True if the value was deleted, otherwise False.
|
|
49
|
+
"""
|
|
50
|
+
deleted = self.tree.delete(value)
|
|
51
|
+
self.balance()
|
|
52
|
+
return deleted
|
|
53
|
+
|
|
54
|
+
def find(self, value: T) -> BinaryNode[T] | None:
|
|
55
|
+
"""
|
|
56
|
+
Find a value in the tree.
|
|
57
|
+
|
|
58
|
+
:param value: The value to find.
|
|
59
|
+
:return: The node containing the value, or None if not found.
|
|
60
|
+
"""
|
|
61
|
+
return self.tree.find(value)
|
|
62
|
+
|
|
63
|
+
def contains(self, value: T) -> bool:
|
|
64
|
+
"""
|
|
65
|
+
Check whether the tree contains a value.
|
|
66
|
+
|
|
67
|
+
:param value: The value to check.
|
|
68
|
+
:return: True if the value exists, otherwise False.
|
|
69
|
+
"""
|
|
70
|
+
return self.tree.contains(value)
|
|
71
|
+
|
|
72
|
+
def __contains__(self, value: T) -> bool:
|
|
73
|
+
return value in self.tree
|
|
74
|
+
|
|
75
|
+
def height(self) -> int:
|
|
76
|
+
"""
|
|
77
|
+
Return the height of the tree.
|
|
78
|
+
|
|
79
|
+
:return: The tree height.
|
|
80
|
+
"""
|
|
81
|
+
return self.tree.height()
|
|
82
|
+
|
|
83
|
+
def count_leaves(self) -> int:
|
|
84
|
+
"""
|
|
85
|
+
Count the leaf nodes in the tree.
|
|
86
|
+
|
|
87
|
+
:return: The number of leaf nodes.
|
|
88
|
+
"""
|
|
89
|
+
return self.tree.count_leaves()
|
|
90
|
+
|
|
91
|
+
def count_internal_nodes(self) -> int:
|
|
92
|
+
"""
|
|
93
|
+
Count the internal nodes in the tree.
|
|
94
|
+
|
|
95
|
+
:return: The number of internal nodes.
|
|
96
|
+
"""
|
|
97
|
+
return self.tree.count_internal_nodes()
|
|
98
|
+
|
|
99
|
+
def get_root(self) -> BinaryNode[T] | None:
|
|
100
|
+
"""
|
|
101
|
+
Return the root node.
|
|
102
|
+
|
|
103
|
+
:return: The root node, or None if the tree is empty.
|
|
104
|
+
"""
|
|
105
|
+
return self.tree.get_root()
|
|
106
|
+
|
|
107
|
+
def get_left_subtree(self) -> BinaryTree[T]:
|
|
108
|
+
"""
|
|
109
|
+
Return the left subtree.
|
|
110
|
+
|
|
111
|
+
:return: The left subtree.
|
|
112
|
+
"""
|
|
113
|
+
return self.tree.get_left_subtree()
|
|
114
|
+
|
|
115
|
+
def get_right_subtree(self) -> BinaryTree[T]:
|
|
116
|
+
"""
|
|
117
|
+
Return the right subtree.
|
|
118
|
+
|
|
119
|
+
:return: The right subtree.
|
|
120
|
+
"""
|
|
121
|
+
return self.tree.get_right_subtree()
|
|
122
|
+
|
|
123
|
+
def _set_left_subtree(self, subtree: BinaryTree[T]) -> None:
|
|
124
|
+
"""
|
|
125
|
+
Set the left subtree.
|
|
126
|
+
|
|
127
|
+
:param subtree: The tree to use as the left subtree.
|
|
128
|
+
"""
|
|
129
|
+
self.tree._set_left_subtree(subtree)
|
|
130
|
+
|
|
131
|
+
def _set_right_subtree(self, subtree: BinaryTree[T]) -> None:
|
|
132
|
+
"""
|
|
133
|
+
Set the right subtree.
|
|
134
|
+
|
|
135
|
+
:param subtree: The tree to use as the right subtree.
|
|
136
|
+
"""
|
|
137
|
+
self.tree._set_right_subtree(subtree)
|
|
138
|
+
|
|
139
|
+
def right_rotate(self) -> BinaryTree[T]:
|
|
140
|
+
"""
|
|
141
|
+
Perform a right rotation.
|
|
142
|
+
|
|
143
|
+
:return: The tree after the rotation.
|
|
144
|
+
"""
|
|
145
|
+
self.tree = self.tree.right_rotate()
|
|
146
|
+
return self.tree
|
|
147
|
+
|
|
148
|
+
def left_rotate(self) -> BinaryTree[T]:
|
|
149
|
+
"""
|
|
150
|
+
Perform a left rotation.
|
|
151
|
+
|
|
152
|
+
:return: The tree after the rotation.
|
|
153
|
+
"""
|
|
154
|
+
self.tree = self.tree.left_rotate()
|
|
155
|
+
return self.tree
|
|
156
|
+
|
|
157
|
+
def invert_tree(self) -> None:
|
|
158
|
+
"""
|
|
159
|
+
Invert the tree.
|
|
160
|
+
"""
|
|
161
|
+
self.tree.invert_tree()
|
|
162
|
+
|
|
163
|
+
def is_empty(self) -> bool:
|
|
164
|
+
"""
|
|
165
|
+
Check whether the tree is empty.
|
|
166
|
+
|
|
167
|
+
:return: True if the tree is empty, otherwise False.
|
|
168
|
+
"""
|
|
169
|
+
return self.tree.is_empty()
|
|
170
|
+
|
|
171
|
+
def clear(self) -> None:
|
|
172
|
+
"""
|
|
173
|
+
Clear the tree.
|
|
174
|
+
"""
|
|
175
|
+
self.tree.clear()
|
|
176
|
+
|
|
177
|
+
def size(self) -> int:
|
|
178
|
+
"""
|
|
179
|
+
Return the number of nodes in the tree.
|
|
180
|
+
|
|
181
|
+
:return: The tree size.
|
|
182
|
+
"""
|
|
183
|
+
return self.tree.size()
|
|
184
|
+
|
|
185
|
+
def __len__(self) -> int:
|
|
186
|
+
return len(self.tree)
|
|
187
|
+
|
|
188
|
+
def __bool__(self) -> bool:
|
|
189
|
+
return bool(self.tree)
|
|
190
|
+
|
|
191
|
+
def _balance(self, tree: BinaryTree[T]) -> BinaryTree[T]:
|
|
192
|
+
"""
|
|
193
|
+
Recursively balance the given tree.
|
|
194
|
+
|
|
195
|
+
:param tree: The tree to balance.
|
|
196
|
+
:return: The balanced tree.
|
|
197
|
+
"""
|
|
198
|
+
if tree.is_empty():
|
|
199
|
+
return tree
|
|
200
|
+
|
|
201
|
+
left_subtree = self._balance(tree.get_left_subtree())
|
|
202
|
+
right_subtree = self._balance(tree.get_right_subtree())
|
|
203
|
+
|
|
204
|
+
tree._set_left_subtree(left_subtree)
|
|
205
|
+
tree._set_right_subtree(right_subtree)
|
|
206
|
+
|
|
207
|
+
return self._rebalance(tree)
|
|
208
|
+
|
|
209
|
+
def _rebalance(self, tree: BinaryTree[T]) -> BinaryTree[T]:
|
|
210
|
+
"""
|
|
211
|
+
Rebalance the given tree if it violates the AVL balance condition.
|
|
212
|
+
|
|
213
|
+
:param tree: The tree to rebalance.
|
|
214
|
+
:return: The rebalanced tree.
|
|
215
|
+
"""
|
|
216
|
+
balance_factor = self._calculate_balance_factor(tree)
|
|
217
|
+
|
|
218
|
+
if balance_factor > self.balance_factor:
|
|
219
|
+
left_subtree = tree.get_left_subtree()
|
|
220
|
+
|
|
221
|
+
if self._calculate_balance_factor(left_subtree) < 0:
|
|
222
|
+
left_subtree.left_rotate()
|
|
223
|
+
tree._set_left_subtree(left_subtree)
|
|
224
|
+
|
|
225
|
+
return tree.right_rotate()
|
|
226
|
+
|
|
227
|
+
if balance_factor < -self.balance_factor:
|
|
228
|
+
right_subtree = tree.get_right_subtree()
|
|
229
|
+
|
|
230
|
+
if self._calculate_balance_factor(right_subtree) > 0:
|
|
231
|
+
right_subtree.right_rotate()
|
|
232
|
+
tree._set_right_subtree(right_subtree)
|
|
233
|
+
|
|
234
|
+
return tree.left_rotate()
|
|
235
|
+
|
|
236
|
+
return tree
|
|
237
|
+
|
|
238
|
+
def _calculate_balance_factor(self, tree: BinaryTree[T]) -> int:
|
|
239
|
+
"""
|
|
240
|
+
Return the AVL balance factor of the tree.
|
|
241
|
+
|
|
242
|
+
:param tree: The tree whose balance factor is calculated.
|
|
243
|
+
:return: The height difference between the left and right subtrees.
|
|
244
|
+
"""
|
|
245
|
+
return tree.get_left_subtree().height() - tree.get_right_subtree().height()
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
|
+
from typing import Protocol
|
|
2
3
|
|
|
3
4
|
from stepps.nodes import BinaryNode
|
|
4
5
|
from stepps.trees.tree import Tree
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
class BinaryTree[T](Tree[T]):
|
|
8
|
+
class BinaryTree[T](Tree[T], Protocol):
|
|
8
9
|
"""
|
|
9
10
|
Define the interface for binary tree implementations.
|
|
10
11
|
"""
|
|
@@ -116,19 +117,39 @@ class BinaryTree[T](Tree[T]):
|
|
|
116
117
|
...
|
|
117
118
|
|
|
118
119
|
@abstractmethod
|
|
119
|
-
def right_rotate(self) -> "BinaryTree[T]
|
|
120
|
+
def right_rotate(self) -> "BinaryTree[T]":
|
|
120
121
|
"""
|
|
121
122
|
Perform a right rotation on the tree.
|
|
122
123
|
|
|
123
|
-
:return: The
|
|
124
|
+
:return: The tree after the rotation.
|
|
124
125
|
"""
|
|
125
126
|
...
|
|
126
127
|
|
|
127
128
|
@abstractmethod
|
|
128
|
-
def left_rotate(self) -> "BinaryTree[T]
|
|
129
|
+
def left_rotate(self) -> "BinaryTree[T]":
|
|
129
130
|
"""
|
|
130
131
|
Perform a left rotation on the tree.
|
|
131
132
|
|
|
132
|
-
:return: The
|
|
133
|
+
:return: The tree after the rotation.
|
|
134
|
+
"""
|
|
135
|
+
...
|
|
136
|
+
|
|
137
|
+
@abstractmethod
|
|
138
|
+
def _set_left_subtree(self, subtree: "BinaryTree[T]") -> None:
|
|
139
|
+
"""
|
|
140
|
+
Set the left subtree.
|
|
141
|
+
|
|
142
|
+
:param subtree: The tree to use as the left subtree.
|
|
143
|
+
:return: ``None``.
|
|
144
|
+
"""
|
|
145
|
+
...
|
|
146
|
+
|
|
147
|
+
@abstractmethod
|
|
148
|
+
def _set_right_subtree(self, subtree: "BinaryTree[T]") -> None:
|
|
149
|
+
"""
|
|
150
|
+
Set the right subtree.
|
|
151
|
+
|
|
152
|
+
:param subtree: The tree to use as the right subtree.
|
|
153
|
+
:return: ``None``.
|
|
133
154
|
"""
|
|
134
155
|
...
|
|
@@ -305,3 +305,27 @@ class BinaryTreeImpl[T](BinaryTree[T]):
|
|
|
305
305
|
self.root = new_root
|
|
306
306
|
|
|
307
307
|
return self
|
|
308
|
+
|
|
309
|
+
@override
|
|
310
|
+
def _set_left_subtree(self, subtree: BinaryTree[T]) -> None:
|
|
311
|
+
"""
|
|
312
|
+
Set the left subtree.
|
|
313
|
+
|
|
314
|
+
:param subtree: The tree to use as the left subtree.
|
|
315
|
+
"""
|
|
316
|
+
if self.root is None:
|
|
317
|
+
return
|
|
318
|
+
|
|
319
|
+
self.root.left = subtree.get_root()
|
|
320
|
+
|
|
321
|
+
@override
|
|
322
|
+
def _set_right_subtree(self, subtree: BinaryTree[T]) -> None:
|
|
323
|
+
"""
|
|
324
|
+
Set the right subtree.
|
|
325
|
+
|
|
326
|
+
:param subtree: The tree to use as the right subtree.
|
|
327
|
+
"""
|
|
328
|
+
if self.root is None:
|
|
329
|
+
return
|
|
330
|
+
|
|
331
|
+
self.root.right = subtree.get_root()
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
from abc import
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import Protocol
|
|
2
3
|
|
|
3
4
|
from stepps.nodes import BinaryNode
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
class Tree[T](
|
|
7
|
+
class Tree[T](Protocol):
|
|
7
8
|
"""
|
|
8
9
|
Define the common interface for tree implementations.
|
|
9
10
|
"""
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
|
+
from typing import Protocol
|
|
2
3
|
|
|
3
4
|
from stepps.nodes import BinaryNode
|
|
4
5
|
from stepps.visualizer.tree_visualizer import TreeVisualizer
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
class CliTreeVisualizer[T](TreeVisualizer[BinaryNode[T] | None]):
|
|
8
|
+
class CliTreeVisualizer[T](TreeVisualizer[BinaryNode[T] | None], Protocol):
|
|
8
9
|
"""
|
|
9
10
|
Define the interface for CLI-based binary tree visualization.
|
|
10
11
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stepps
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Useful algorithms in Python
|
|
5
5
|
Author-email: Suhas Krishna Srivastava <suhas.srivastava@vaastav.tech>, Trinay Mitra <trinay.mitra@vaastav.tech>
|
|
6
6
|
Maintainer-email: Suhas Krishna Srivastava <suhas.srivastava@vaastav.tech>
|
|
@@ -7,16 +7,6 @@ src/stepps.egg-info/PKG-INFO
|
|
|
7
7
|
src/stepps.egg-info/SOURCES.txt
|
|
8
8
|
src/stepps.egg-info/dependency_links.txt
|
|
9
9
|
src/stepps.egg-info/top_level.txt
|
|
10
|
-
src/stepps/TreeBuilder/__init__.py
|
|
11
|
-
src/stepps/TreeBuilder/inorder_tree_builder.py
|
|
12
|
-
src/stepps/TreeBuilder/inorder_tree_builder_impl.py
|
|
13
|
-
src/stepps/TreeBuilder/level_order_tree_builder.py
|
|
14
|
-
src/stepps/TreeBuilder/level_order_tree_builder_impl.py
|
|
15
|
-
src/stepps/TreeBuilder/postorder_tree_builder.py
|
|
16
|
-
src/stepps/TreeBuilder/postorder_tree_builder_impl.py
|
|
17
|
-
src/stepps/TreeBuilder/preorder_tree_builder.py
|
|
18
|
-
src/stepps/TreeBuilder/preorder_tree_builder_impl.py
|
|
19
|
-
src/stepps/TreeBuilder/tree_builder.py
|
|
20
10
|
src/stepps/iterators/__init__.py
|
|
21
11
|
src/stepps/iterators/base_iterator.py
|
|
22
12
|
src/stepps/iterators/inorder.py
|
|
@@ -25,16 +15,30 @@ src/stepps/iterators/postorder.py
|
|
|
25
15
|
src/stepps/iterators/preorder.py
|
|
26
16
|
src/stepps/nodes/__init__.py
|
|
27
17
|
src/stepps/nodes/binary_node.py
|
|
18
|
+
src/stepps/tree_builder/__init__.py
|
|
19
|
+
src/stepps/tree_builder/inorder_tree_builder.py
|
|
20
|
+
src/stepps/tree_builder/inorder_tree_builder_impl.py
|
|
21
|
+
src/stepps/tree_builder/level_order_tree_builder.py
|
|
22
|
+
src/stepps/tree_builder/level_order_tree_builder_impl.py
|
|
23
|
+
src/stepps/tree_builder/postorder_tree_builder.py
|
|
24
|
+
src/stepps/tree_builder/postorder_tree_builder_impl.py
|
|
25
|
+
src/stepps/tree_builder/preorder_tree_builder.py
|
|
26
|
+
src/stepps/tree_builder/preorder_tree_builder_impl.py
|
|
27
|
+
src/stepps/tree_builder/tree_builder.py
|
|
28
28
|
src/stepps/trees/__init__.py
|
|
29
29
|
src/stepps/trees/binary_tree.py
|
|
30
30
|
src/stepps/trees/binary_tree_impl.py
|
|
31
31
|
src/stepps/trees/bst.py
|
|
32
32
|
src/stepps/trees/bst_impl.py
|
|
33
33
|
src/stepps/trees/tree.py
|
|
34
|
+
src/stepps/trees/balanced/__init__.py
|
|
35
|
+
src/stepps/trees/balanced/avl.py
|
|
36
|
+
src/stepps/trees/balanced/avl_impl.py
|
|
34
37
|
src/stepps/visualizer/__init__.py
|
|
35
38
|
src/stepps/visualizer/cli_visualizer.py
|
|
36
39
|
src/stepps/visualizer/cli_visualizer_impl.py
|
|
37
40
|
src/stepps/visualizer/tree_visualizer.py
|
|
41
|
+
tests/test_avl.py
|
|
38
42
|
tests/test_binary_tree.py
|
|
39
43
|
tests/test_bst.py
|
|
40
44
|
tests/test_inorder_tree_builder.py
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
from stepps.iterators.levelorder import LevelOrderIterator
|
|
2
|
+
from stepps.nodes import BinaryNode
|
|
3
|
+
from stepps.trees.balanced.avl_impl import AVLImpl
|
|
4
|
+
from stepps.trees.binary_tree_impl import BinaryTreeImpl
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def create_tree(root: BinaryNode[int], size: int) -> BinaryTreeImpl[int]:
|
|
8
|
+
tree = BinaryTreeImpl[int](LevelOrderIterator)
|
|
9
|
+
tree.root = root
|
|
10
|
+
tree._size = size
|
|
11
|
+
|
|
12
|
+
return tree
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# =====================================================
|
|
16
|
+
# Basic Cases
|
|
17
|
+
# =====================================================
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_balance_empty_tree():
|
|
21
|
+
tree = BinaryTreeImpl[int](LevelOrderIterator)
|
|
22
|
+
avl = AVLImpl[int](tree)
|
|
23
|
+
|
|
24
|
+
result = avl.balance()
|
|
25
|
+
|
|
26
|
+
assert result is tree
|
|
27
|
+
assert result.is_empty()
|
|
28
|
+
assert result.size() == 0
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_balance_single_node_tree():
|
|
32
|
+
tree = create_tree(BinaryNode(10), 1)
|
|
33
|
+
avl = AVLImpl[int](tree)
|
|
34
|
+
|
|
35
|
+
result = avl.balance()
|
|
36
|
+
|
|
37
|
+
assert result is tree
|
|
38
|
+
assert result.root is not None
|
|
39
|
+
assert result.root.value == 10
|
|
40
|
+
assert result.root.left is None
|
|
41
|
+
assert result.root.right is None
|
|
42
|
+
assert result.size() == 1
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_balance_already_balanced_tree():
|
|
46
|
+
root = BinaryNode(20)
|
|
47
|
+
root.left = BinaryNode(10)
|
|
48
|
+
root.right = BinaryNode(30)
|
|
49
|
+
|
|
50
|
+
tree = create_tree(root, 3)
|
|
51
|
+
avl = AVLImpl[int](tree)
|
|
52
|
+
|
|
53
|
+
result = avl.balance()
|
|
54
|
+
|
|
55
|
+
assert result is tree
|
|
56
|
+
assert result.root is not None
|
|
57
|
+
assert result.root.value == 20
|
|
58
|
+
|
|
59
|
+
assert result.root.left is not None
|
|
60
|
+
assert result.root.left.value == 10
|
|
61
|
+
|
|
62
|
+
assert result.root.right is not None
|
|
63
|
+
assert result.root.right.value == 30
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# =====================================================
|
|
67
|
+
# Basic AVL Rotation Cases
|
|
68
|
+
# =====================================================
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_balance_ll_case():
|
|
72
|
+
root = BinaryNode(30)
|
|
73
|
+
root.left = BinaryNode(20)
|
|
74
|
+
root.left.left = BinaryNode(10)
|
|
75
|
+
|
|
76
|
+
tree = create_tree(root, 3)
|
|
77
|
+
avl = AVLImpl[int](tree)
|
|
78
|
+
|
|
79
|
+
result = avl.balance()
|
|
80
|
+
|
|
81
|
+
assert result.root is not None
|
|
82
|
+
assert result.root.value == 20
|
|
83
|
+
|
|
84
|
+
assert result.root.left is not None
|
|
85
|
+
assert result.root.left.value == 10
|
|
86
|
+
|
|
87
|
+
assert result.root.right is not None
|
|
88
|
+
assert result.root.right.value == 30
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_balance_rr_case():
|
|
92
|
+
root = BinaryNode(10)
|
|
93
|
+
root.right = BinaryNode(20)
|
|
94
|
+
root.right.right = BinaryNode(30)
|
|
95
|
+
|
|
96
|
+
tree = create_tree(root, 3)
|
|
97
|
+
avl = AVLImpl[int](tree)
|
|
98
|
+
|
|
99
|
+
result = avl.balance()
|
|
100
|
+
|
|
101
|
+
assert result.root is not None
|
|
102
|
+
assert result.root.value == 20
|
|
103
|
+
|
|
104
|
+
assert result.root.left is not None
|
|
105
|
+
assert result.root.left.value == 10
|
|
106
|
+
|
|
107
|
+
assert result.root.right is not None
|
|
108
|
+
assert result.root.right.value == 30
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_balance_lr_case():
|
|
112
|
+
root = BinaryNode(30)
|
|
113
|
+
root.left = BinaryNode(10)
|
|
114
|
+
root.left.right = BinaryNode(20)
|
|
115
|
+
|
|
116
|
+
tree = create_tree(root, 3)
|
|
117
|
+
avl = AVLImpl[int](tree)
|
|
118
|
+
|
|
119
|
+
result = avl.balance()
|
|
120
|
+
|
|
121
|
+
assert result.root is not None
|
|
122
|
+
assert result.root.value == 20
|
|
123
|
+
|
|
124
|
+
assert result.root.left is not None
|
|
125
|
+
assert result.root.left.value == 10
|
|
126
|
+
|
|
127
|
+
assert result.root.right is not None
|
|
128
|
+
assert result.root.right.value == 30
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_balance_rl_case():
|
|
132
|
+
root = BinaryNode(10)
|
|
133
|
+
root.right = BinaryNode(30)
|
|
134
|
+
root.right.left = BinaryNode(20)
|
|
135
|
+
|
|
136
|
+
tree = create_tree(root, 3)
|
|
137
|
+
avl = AVLImpl[int](tree)
|
|
138
|
+
|
|
139
|
+
result = avl.balance()
|
|
140
|
+
|
|
141
|
+
assert result.root is not None
|
|
142
|
+
assert result.root.value == 20
|
|
143
|
+
|
|
144
|
+
assert result.root.left is not None
|
|
145
|
+
assert result.root.left.value == 10
|
|
146
|
+
|
|
147
|
+
assert result.root.right is not None
|
|
148
|
+
assert result.root.right.value == 30
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# =====================================================
|
|
152
|
+
# Nested Subtree Cases
|
|
153
|
+
# =====================================================
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_balance_ll_case_in_left_subtree():
|
|
157
|
+
root = BinaryNode(100)
|
|
158
|
+
root.left = BinaryNode(50)
|
|
159
|
+
root.left.left = BinaryNode(30)
|
|
160
|
+
root.left.left.left = BinaryNode(20)
|
|
161
|
+
|
|
162
|
+
tree = create_tree(root, 4)
|
|
163
|
+
avl = AVLImpl[int](tree)
|
|
164
|
+
|
|
165
|
+
result = avl.balance()
|
|
166
|
+
|
|
167
|
+
assert result.root is not None
|
|
168
|
+
assert result.root.value == 30
|
|
169
|
+
|
|
170
|
+
assert result.root.left is not None
|
|
171
|
+
assert result.root.left.value == 20
|
|
172
|
+
|
|
173
|
+
assert result.root.right is not None
|
|
174
|
+
assert result.root.right.value == 100
|
|
175
|
+
|
|
176
|
+
assert result.root.right.left is not None
|
|
177
|
+
assert result.root.right.left.value == 50
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def test_balance_rr_case_in_right_subtree():
|
|
181
|
+
root = BinaryNode(100)
|
|
182
|
+
root.right = BinaryNode(150)
|
|
183
|
+
root.right.right = BinaryNode(170)
|
|
184
|
+
root.right.right.right = BinaryNode(180)
|
|
185
|
+
|
|
186
|
+
tree = create_tree(root, 4)
|
|
187
|
+
avl = AVLImpl[int](tree)
|
|
188
|
+
|
|
189
|
+
result = avl.balance()
|
|
190
|
+
|
|
191
|
+
assert result.root is not None
|
|
192
|
+
assert result.root.value == 170
|
|
193
|
+
|
|
194
|
+
assert result.root.left is not None
|
|
195
|
+
assert result.root.left.value == 100
|
|
196
|
+
|
|
197
|
+
assert result.root.left.right is not None
|
|
198
|
+
assert result.root.left.right.value == 150
|
|
199
|
+
|
|
200
|
+
assert result.root.right is not None
|
|
201
|
+
assert result.root.right.value == 180
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def test_balance_lr_case_in_left_subtree():
|
|
205
|
+
root = BinaryNode(100)
|
|
206
|
+
root.left = BinaryNode(50)
|
|
207
|
+
root.left.left = BinaryNode(30)
|
|
208
|
+
root.left.left.right = BinaryNode(40)
|
|
209
|
+
|
|
210
|
+
tree = create_tree(root, 4)
|
|
211
|
+
avl = AVLImpl[int](tree)
|
|
212
|
+
|
|
213
|
+
result = avl.balance()
|
|
214
|
+
|
|
215
|
+
assert result.root is not None
|
|
216
|
+
assert result.root.value == 40
|
|
217
|
+
|
|
218
|
+
assert result.root.left is not None
|
|
219
|
+
assert result.root.left.value == 30
|
|
220
|
+
|
|
221
|
+
assert result.root.right is not None
|
|
222
|
+
assert result.root.right.value == 100
|
|
223
|
+
|
|
224
|
+
assert result.root.right.left is not None
|
|
225
|
+
assert result.root.right.left.value == 50
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def test_balance_rl_case_in_right_subtree():
|
|
229
|
+
root = BinaryNode(100)
|
|
230
|
+
root.right = BinaryNode(150)
|
|
231
|
+
root.right.right = BinaryNode(170)
|
|
232
|
+
root.right.right.left = BinaryNode(160)
|
|
233
|
+
|
|
234
|
+
tree = create_tree(root, 4)
|
|
235
|
+
avl = AVLImpl[int](tree)
|
|
236
|
+
|
|
237
|
+
result = avl.balance()
|
|
238
|
+
|
|
239
|
+
assert result.root is not None
|
|
240
|
+
assert result.root.value == 160
|
|
241
|
+
|
|
242
|
+
assert result.root.left is not None
|
|
243
|
+
assert result.root.left.value == 100
|
|
244
|
+
|
|
245
|
+
assert result.root.left.right is not None
|
|
246
|
+
assert result.root.left.right.value == 150
|
|
247
|
+
|
|
248
|
+
assert result.root.right is not None
|
|
249
|
+
assert result.root.right.value == 170
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
# =====================================================
|
|
253
|
+
# Larger Trees
|
|
254
|
+
# =====================================================
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def test_balance_left_heavy_tree():
|
|
258
|
+
root = BinaryNode(50)
|
|
259
|
+
|
|
260
|
+
root.left = BinaryNode(30)
|
|
261
|
+
root.left.left = BinaryNode(20)
|
|
262
|
+
root.left.left.left = BinaryNode(10)
|
|
263
|
+
root.left.right = BinaryNode(40)
|
|
264
|
+
|
|
265
|
+
root.right = BinaryNode(70)
|
|
266
|
+
root.right.left = BinaryNode(60)
|
|
267
|
+
root.right.right = BinaryNode(80)
|
|
268
|
+
|
|
269
|
+
tree = create_tree(root, 8)
|
|
270
|
+
avl = AVLImpl[int](tree)
|
|
271
|
+
|
|
272
|
+
result = avl.balance()
|
|
273
|
+
|
|
274
|
+
assert result.root is not None
|
|
275
|
+
assert result.height() <= 3
|
|
276
|
+
assert result.size() == 8
|
|
277
|
+
|
|
278
|
+
for value in (10, 20, 30, 40, 50, 60, 70, 80):
|
|
279
|
+
assert result.contains(value)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def test_balance_right_heavy_tree():
|
|
283
|
+
root = BinaryNode(50)
|
|
284
|
+
|
|
285
|
+
root.left = BinaryNode(30)
|
|
286
|
+
root.left.left = BinaryNode(20)
|
|
287
|
+
root.left.right = BinaryNode(40)
|
|
288
|
+
|
|
289
|
+
root.right = BinaryNode(70)
|
|
290
|
+
root.right.right = BinaryNode(80)
|
|
291
|
+
root.right.right.right = BinaryNode(90)
|
|
292
|
+
|
|
293
|
+
tree = create_tree(root, 7)
|
|
294
|
+
avl = AVLImpl[int](tree)
|
|
295
|
+
|
|
296
|
+
result = avl.balance()
|
|
297
|
+
|
|
298
|
+
assert result.root is not None
|
|
299
|
+
assert result.height() <= 3
|
|
300
|
+
assert result.size() == 7
|
|
301
|
+
|
|
302
|
+
for value in (20, 30, 40, 50, 70, 80, 90):
|
|
303
|
+
assert result.contains(value)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def test_balance_complex_tree():
|
|
307
|
+
root = BinaryNode(50)
|
|
308
|
+
|
|
309
|
+
root.left = BinaryNode(30)
|
|
310
|
+
root.left.left = BinaryNode(20)
|
|
311
|
+
root.left.right = BinaryNode(40)
|
|
312
|
+
root.left.left.left = BinaryNode(10)
|
|
313
|
+
|
|
314
|
+
root.right = BinaryNode(70)
|
|
315
|
+
root.right.right = BinaryNode(80)
|
|
316
|
+
root.right.right.right = BinaryNode(90)
|
|
317
|
+
|
|
318
|
+
tree = create_tree(root, 8)
|
|
319
|
+
avl = AVLImpl[int](tree)
|
|
320
|
+
|
|
321
|
+
result = avl.balance()
|
|
322
|
+
|
|
323
|
+
assert result.root is not None
|
|
324
|
+
assert result.height() <= 3
|
|
325
|
+
assert result.size() == 8
|
|
326
|
+
|
|
327
|
+
for value in (10, 20, 30, 40, 50, 70, 80, 90):
|
|
328
|
+
assert result.contains(value)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# =====================================================
|
|
332
|
+
# Tree Structure Preservation
|
|
333
|
+
# =====================================================
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def test_balance_preserves_all_nodes():
|
|
337
|
+
root = BinaryNode(50)
|
|
338
|
+
|
|
339
|
+
root.left = BinaryNode(30)
|
|
340
|
+
root.left.left = BinaryNode(20)
|
|
341
|
+
root.left.right = BinaryNode(40)
|
|
342
|
+
|
|
343
|
+
root.right = BinaryNode(70)
|
|
344
|
+
root.right.left = BinaryNode(60)
|
|
345
|
+
root.right.right = BinaryNode(80)
|
|
346
|
+
|
|
347
|
+
tree = create_tree(root, 7)
|
|
348
|
+
avl = AVLImpl[int](tree)
|
|
349
|
+
|
|
350
|
+
result = avl.balance()
|
|
351
|
+
|
|
352
|
+
assert result.size() == 7
|
|
353
|
+
|
|
354
|
+
for value in (20, 30, 40, 50, 60, 70, 80):
|
|
355
|
+
assert result.contains(value)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def test_balance_returns_same_tree_object():
|
|
359
|
+
root = BinaryNode(30)
|
|
360
|
+
root.left = BinaryNode(20)
|
|
361
|
+
root.left.left = BinaryNode(10)
|
|
362
|
+
|
|
363
|
+
tree = create_tree(root, 3)
|
|
364
|
+
avl = AVLImpl[int](tree)
|
|
365
|
+
|
|
366
|
+
result = avl.balance()
|
|
367
|
+
|
|
368
|
+
assert result is tree
|
|
@@ -390,3 +390,78 @@ def test_left_rotate_without_right_child():
|
|
|
390
390
|
assert result is tree
|
|
391
391
|
assert tree.root is not None
|
|
392
392
|
assert tree.root.value == 30
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
# =====================================================
|
|
396
|
+
# Tree Subtree Assignment
|
|
397
|
+
# =====================================================
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def test_set_left_subtree(tree):
|
|
401
|
+
subtree = BinaryTreeImpl[int](LevelOrderIterator)
|
|
402
|
+
|
|
403
|
+
subtree.root = BinaryNode(30)
|
|
404
|
+
subtree.root.left = BinaryNode(20)
|
|
405
|
+
subtree.root.right = BinaryNode(40)
|
|
406
|
+
subtree._size = 3
|
|
407
|
+
|
|
408
|
+
tree._set_left_subtree(subtree)
|
|
409
|
+
|
|
410
|
+
assert tree.root is not None
|
|
411
|
+
assert tree.root.left is subtree.root
|
|
412
|
+
assert tree.root.left.value == 30
|
|
413
|
+
|
|
414
|
+
assert tree.root.left.left is not None
|
|
415
|
+
assert tree.root.left.left.value == 20
|
|
416
|
+
|
|
417
|
+
assert tree.root.left.right is not None
|
|
418
|
+
assert tree.root.left.right.value == 40
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def test_set_right_subtree(tree):
|
|
422
|
+
subtree = BinaryTreeImpl[int](LevelOrderIterator)
|
|
423
|
+
|
|
424
|
+
subtree.root = BinaryNode(70)
|
|
425
|
+
subtree.root.left = BinaryNode(60)
|
|
426
|
+
subtree.root.right = BinaryNode(80)
|
|
427
|
+
subtree._size = 3
|
|
428
|
+
|
|
429
|
+
tree._set_right_subtree(subtree)
|
|
430
|
+
|
|
431
|
+
assert tree.root is not None
|
|
432
|
+
assert tree.root.right is subtree.root
|
|
433
|
+
assert tree.root.right.value == 70
|
|
434
|
+
|
|
435
|
+
assert tree.root.right.left is not None
|
|
436
|
+
assert tree.root.right.left.value == 60
|
|
437
|
+
|
|
438
|
+
assert tree.root.right.right is not None
|
|
439
|
+
assert tree.root.right.right.value == 80
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def test_right_rotate_nested_subtree():
|
|
443
|
+
tree = BinaryTreeImpl[int](LevelOrderIterator)
|
|
444
|
+
|
|
445
|
+
root = BinaryNode(100)
|
|
446
|
+
root.left = BinaryNode(50)
|
|
447
|
+
root.left.left = BinaryNode(30)
|
|
448
|
+
root.left.left.left = BinaryNode(20)
|
|
449
|
+
|
|
450
|
+
tree.root = root
|
|
451
|
+
tree._size = 4
|
|
452
|
+
|
|
453
|
+
subtree = tree.get_left_subtree()
|
|
454
|
+
subtree.right_rotate()
|
|
455
|
+
tree._set_left_subtree(subtree)
|
|
456
|
+
|
|
457
|
+
assert tree.root is not None
|
|
458
|
+
assert tree.root.value == 100
|
|
459
|
+
|
|
460
|
+
assert tree.root.left is not None
|
|
461
|
+
assert tree.root.left.value == 30
|
|
462
|
+
|
|
463
|
+
assert tree.root.left.left is not None
|
|
464
|
+
assert tree.root.left.left.value == 20
|
|
465
|
+
|
|
466
|
+
assert tree.root.left.right is not None
|
|
467
|
+
assert tree.root.left.right.value == 50
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from stepps.iterators.levelorder import LevelOrderIterator
|
|
2
|
-
from stepps.
|
|
2
|
+
from stepps.tree_builder.level_order_tree_builder_impl import LevelOrderTreeBuilderImpl
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
def test_build_empty_sequence():
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
from stepps.TreeBuilder.inorder_tree_builder import InOrderTreeBuilder
|
|
2
|
-
from stepps.TreeBuilder.inorder_tree_builder_impl import InOrderTreeBuilderImpl
|
|
3
|
-
from stepps.TreeBuilder.level_order_tree_builder import LevelOrderTreeBuilder
|
|
4
|
-
from stepps.TreeBuilder.level_order_tree_builder_impl import LevelOrderTreeBuilderImpl
|
|
5
|
-
from stepps.TreeBuilder.tree_builder import TreeBuilder
|
|
6
|
-
|
|
7
|
-
__all__ = [
|
|
8
|
-
"InOrderTreeBuilder",
|
|
9
|
-
"InOrderTreeBuilderImpl",
|
|
10
|
-
"LevelOrderTreeBuilder",
|
|
11
|
-
"LevelOrderTreeBuilderImpl",
|
|
12
|
-
"TreeBuilder",
|
|
13
|
-
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|