1
- """
1
+ r """
2
2
A binary search Tree
3
+
4
+ Example
5
+ 8
6
+ / \
7
+ 3 10
8
+ / \ \
9
+ 1 6 14
10
+ / \ /
11
+ 4 7 13
12
+
13
+ >>> t = BinarySearchTree()
14
+ >>> t.insert(8, 3, 6, 1, 10, 14, 13, 4, 7)
15
+ >>> print(" ".join(repr(i.value) for i in t.traversal_tree()))
16
+ 8 3 1 6 4 7 10 14 13
17
+ >>> print(" ".join(repr(i.value) for i in t.traversal_tree(postorder)))
18
+ 1 4 7 6 3 13 14 10 8
19
+ >>> t.remove(20)
20
+ Traceback (most recent call last):
21
+ ...
22
+ ValueError: Value 20 not found
23
+ >>> BinarySearchTree().search(6)
24
+ Traceback (most recent call last):
25
+ ...
26
+ IndexError: Warning: Tree is empty! please use another.
27
+
28
+ Other example:
29
+
30
+ >>> testlist = (8, 3, 6, 1, 10, 14, 13, 4, 7)
31
+ >>> t = BinarySearchTree()
32
+ >>> for i in testlist:
33
+ ... t.insert(i)
34
+
35
+ Prints all the elements of the list in order traversal
36
+ >>> print(t)
37
+ {'8': ({'3': (1, {'6': (4, 7)})}, {'10': (None, {'14': (13, None)})})}
38
+
39
+ Test existence
40
+ >>> t.search(6) is not None
41
+ True
42
+ >>> t.search(-1) is not None
43
+ False
44
+
45
+ >>> t.search(6).is_right
46
+ True
47
+ >>> t.search(1).is_right
48
+ False
49
+
50
+ >>> t.get_max().value
51
+ 14
52
+ >>> t.get_min().value
53
+ 1
54
+ >>> t.empty()
55
+ False
56
+ >>> for i in testlist:
57
+ ... t.remove(i)
58
+ >>> t.empty()
59
+ True
3
60
"""
4
61
5
62
from collections .abc import Iterable
@@ -20,6 +77,10 @@ def __repr__(self) -> str:
20
77
return str (self .value )
21
78
return pformat ({f"{ self .value } " : (self .left , self .right )}, indent = 1 )
22
79
80
+ @property
81
+ def is_right (self ) -> bool :
82
+ return self .parent is not None and self is self .parent .right
83
+
23
84
24
85
class BinarySearchTree :
25
86
def __init__ (self , root : Node | None = None ):
@@ -35,18 +96,13 @@ def __reassign_nodes(self, node: Node, new_children: Node | None) -> None:
35
96
if new_children is not None : # reset its kids
36
97
new_children .parent = node .parent
37
98
if node .parent is not None : # reset its parent
38
- if self .is_right ( node ) : # If it is the right children
99
+ if node .is_right : # If it is the right child
39
100
node .parent .right = new_children
40
101
else :
41
102
node .parent .left = new_children
42
103
else :
43
104
self .root = new_children
44
105
45
- def is_right (self , node : Node ) -> bool :
46
- if node .parent and node .parent .right :
47
- return node == node .parent .right
48
- return False
49
-
50
106
def empty (self ) -> bool :
51
107
return self .root is None
52
108
@@ -119,22 +175,26 @@ def get_min(self, node: Node | None = None) -> Node | None:
119
175
return node
120
176
121
177
def remove (self , value : int ) -> None :
122
- node = self .search (value ) # Look for the node with that label
123
- if node is not None :
124
- if node .left is None and node .right is None : # If it has no children
125
- self .__reassign_nodes (node , None )
126
- elif node .left is None : # Has only right children
127
- self .__reassign_nodes (node , node .right )
128
- elif node .right is None : # Has only left children
129
- self .__reassign_nodes (node , node .left )
130
- else :
131
- tmp_node = self .get_max (
132
- node .left
133
- ) # Gets the max value of the left branch
134
- self .remove (tmp_node .value ) # type: ignore
135
- node .value = (
136
- tmp_node .value # type: ignore
137
- ) # Assigns the value to the node to delete and keep tree structure
178
+ # Look for the node with that label
179
+ node = self .search (value )
180
+ if node is None :
181
+ msg = f"Value { value } not found"
182
+ raise ValueError (msg )
183
+
184
+ if node .left is None and node .right is None : # If it has no children
185
+ self .__reassign_nodes (node , None )
186
+ elif node .left is None : # Has only right children
187
+ self .__reassign_nodes (node , node .right )
188
+ elif node .right is None : # Has only left children
189
+ self .__reassign_nodes (node , node .left )
190
+ else :
191
+ predecessor = self .get_max (
192
+ node .left
193
+ ) # Gets the max value of the left branch
194
+ self .remove (predecessor .value ) # type: ignore
195
+ node .value = (
196
+ predecessor .value # type: ignore
197
+ ) # Assigns the value to the node to delete and keep tree structure
138
198
139
199
def preorder_traverse (self , node : Node | None ) -> Iterable :
140
200
if node is not None :
@@ -177,55 +237,6 @@ def postorder(curr_node: Node | None) -> list[Node]:
177
237
return node_list
178
238
179
239
180
- def binary_search_tree () -> None :
181
- r"""
182
- Example
183
- 8
184
- / \
185
- 3 10
186
- / \ \
187
- 1 6 14
188
- / \ /
189
- 4 7 13
190
-
191
- >>> t = BinarySearchTree()
192
- >>> t.insert(8, 3, 6, 1, 10, 14, 13, 4, 7)
193
- >>> print(" ".join(repr(i.value) for i in t.traversal_tree()))
194
- 8 3 1 6 4 7 10 14 13
195
- >>> print(" ".join(repr(i.value) for i in t.traversal_tree(postorder)))
196
- 1 4 7 6 3 13 14 10 8
197
- >>> BinarySearchTree().search(6)
198
- Traceback (most recent call last):
199
- ...
200
- IndexError: Warning: Tree is empty! please use another.
201
- """
202
- testlist = (8 , 3 , 6 , 1 , 10 , 14 , 13 , 4 , 7 )
203
- t = BinarySearchTree ()
204
- for i in testlist :
205
- t .insert (i )
206
-
207
- # Prints all the elements of the list in order traversal
208
- print (t )
209
-
210
- if t .search (6 ) is not None :
211
- print ("The value 6 exists" )
212
- else :
213
- print ("The value 6 doesn't exist" )
214
-
215
- if t .search (- 1 ) is not None :
216
- print ("The value -1 exists" )
217
- else :
218
- print ("The value -1 doesn't exist" )
219
-
220
- if not t .empty ():
221
- print ("Max Value: " , t .get_max ().value ) # type: ignore
222
- print ("Min Value: " , t .get_min ().value ) # type: ignore
223
-
224
- for i in testlist :
225
- t .remove (i )
226
- print (t )
227
-
228
-
229
240
if __name__ == "__main__" :
230
241
import doctest
231
242
0 commit comments