1- """
1+ r """
22A 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
360"""
461
562from collections .abc import Iterable
@@ -20,6 +77,10 @@ def __repr__(self) -> str:
2077 return str (self .value )
2178 return pformat ({f"{ self .value } " : (self .left , self .right )}, indent = 1 )
2279
80+ @property
81+ def is_right (self ) -> bool :
82+ return self .parent is not None and self is self .parent .right
83+
2384
2485class BinarySearchTree :
2586 def __init__ (self , root : Node | None = None ):
@@ -35,18 +96,13 @@ def __reassign_nodes(self, node: Node, new_children: Node | None) -> None:
3596 if new_children is not None : # reset its kids
3697 new_children .parent = node .parent
3798 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
39100 node .parent .right = new_children
40101 else :
41102 node .parent .left = new_children
42103 else :
43104 self .root = new_children
44105
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-
50106 def empty (self ) -> bool :
51107 return self .root is None
52108
@@ -119,22 +175,26 @@ def get_min(self, node: Node | None = None) -> Node | None:
119175 return node
120176
121177 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
138198
139199 def preorder_traverse (self , node : Node | None ) -> Iterable :
140200 if node is not None :
@@ -177,55 +237,6 @@ def postorder(curr_node: Node | None) -> list[Node]:
177237 return node_list
178238
179239
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-
229240if __name__ == "__main__" :
230241 import doctest
231242
0 commit comments