1+ class node :
2+ def __init__ (self ,value = None ):
3+ self .value = value
4+ self .left_child = None
5+ self .right_child = None
6+ self .parent = None # pointer to parent node in tree
7+ 8+ class binary_search_tree :
9+ def __init__ (self ):
10+ self .root = None
11+ 12+ def insert (self ,value ):
13+ if self .root == None :
14+ self .root = node (value )
15+ else :
16+ self ._insert (value ,self .root )
17+ 18+ def _insert (self ,value ,cur_node ):
19+ if value < cur_node .value :
20+ if cur_node .left_child == None :
21+ cur_node .left_child = node (value )
22+ cur_node .left_child .parent = cur_node # set parent
23+ else :
24+ self ._insert (value ,cur_node .left_child )
25+ elif value > cur_node .value :
26+ if cur_node .right_child == None :
27+ cur_node .right_child = node (value )
28+ cur_node .right_child .parent = cur_node # set parent
29+ else :
30+ self ._insert (value ,cur_node .right_child )
31+ else :
32+ print ("Value already in tree!" )
33+ 34+ def print_tree (self ):
35+ if self .root != None :
36+ self ._print_tree (self .root )
37+ 38+ def _print_tree (self ,cur_node ):
39+ if cur_node != None :
40+ self ._print_tree (cur_node .left_child )
41+ print (str (cur_node .value ))
42+ self ._print_tree (cur_node .right_child )
43+ 44+ def height (self ):
45+ if self .root != None :
46+ return self ._height (self .root ,0 )
47+ else :
48+ return 0
49+ 50+ def _height (self ,cur_node ,cur_height ):
51+ if cur_node == None : return cur_height
52+ left_height = self ._height (cur_node .left_child ,cur_height + 1 )
53+ right_height = self ._height (cur_node .right_child ,cur_height + 1 )
54+ return max (left_height ,right_height )
55+ 56+ def find (self ,value ):
57+ if self .root != None :
58+ return self ._find (value ,self .root )
59+ else :
60+ return None
61+ 62+ def _find (self ,value ,cur_node ):
63+ if value == cur_node .value :
64+ return cur_node
65+ elif value < cur_node .value and cur_node .left_child != None :
66+ return self ._find (value ,cur_node .left_child )
67+ elif value > cur_node .value and cur_node .right_child != None :
68+ return self ._find (value ,cur_node .right_child )
69+ 70+ def delete_value (self ,value ):
71+ return self .delete_node (self .find (value ))
72+ 73+ def delete_node (self ,node ):
74+ 75+ ## -----
76+ # Improvements since prior lesson
77+ 78+ # Protect against deleting a node not found in the tree
79+ if node == None or self .find (node .value )== None :
80+ print ("Node to be deleted not found in the tree!" )
81+ return None
82+ ## -----
83+ 84+ # returns the node with min value in tree rooted at input node
85+ def min_value_node (n ):
86+ current = n
87+ while current .left_child != None :
88+ current = current .left_child
89+ return current
90+ 91+ # returns the number of children for the specified node
92+ def num_children (n ):
93+ num_children = 0
94+ if n .left_child != None : num_children += 1
95+ if n .right_child != None : num_children += 1
96+ return num_children
97+ 98+ # get the parent of the node to be deleted
99+ node_parent = node .parent
100+ 101+ # get the number of children of the node to be deleted
102+ node_children = num_children (node )
103+ 104+ # break operation into different cases based on the
105+ # structure of the tree & node to be deleted
106+ 107+ # CASE 1 (node has no children)
108+ if node_children == 0 :
109+ 110+ # Added this if statement post-video, previously if you
111+ # deleted the root node it would delete entire tree.
112+ if node_parent != None :
113+ # remove reference to the node from the parent
114+ if node_parent .left_child == node :
115+ node_parent .left_child = None
116+ else :
117+ node_parent .right_child = None
118+ else :
119+ self .root = None
120+ 121+ # CASE 2 (node has a single child)
122+ if node_children == 1 :
123+ 124+ # get the single child node
125+ if node .left_child != None :
126+ child = node .left_child
127+ else :
128+ child = node .right_child
129+ 130+ # Added this if statement post-video, previously if you
131+ # deleted the root node it would delete entire tree.
132+ if node_parent != None :
133+ # replace the node to be deleted with its child
134+ if node_parent .left_child == node :
135+ node_parent .left_child = child
136+ else :
137+ node_parent .right_child = child
138+ else :
139+ self .root = child
140+ 141+ # correct the parent pointer in node
142+ child .parent = node_parent
143+ 144+ # CASE 3 (node has two children)
145+ if node_children == 2 :
146+ 147+ # get the inorder successor of the deleted node
148+ successor = min_value_node (node .right_child )
149+ 150+ # copy the inorder successor's value to the node formerly
151+ # holding the value we wished to delete
152+ node .value = successor .value
153+ 154+ # delete the inorder successor now that it's value was
155+ # copied into the other node
156+ self .delete_node (successor )
157+ 158+ def search (self ,value ):
159+ if self .root != None :
160+ return self ._search (value ,self .root )
161+ else :
162+ return False
163+ 164+ def _search (self ,value ,cur_node ):
165+ if value == cur_node .value :
166+ return True
167+ elif value < cur_node .value and cur_node .left_child != None :
168+ return self ._search (value ,cur_node .left_child )
169+ elif value > cur_node .value and cur_node .right_child != None :
170+ return self ._search (value ,cur_node .right_child )
171+ return False
0 commit comments