-
Notifications
You must be signed in to change notification settings - Fork 1k
/
Copy pathbstree.py
347 lines (274 loc) · 10.5 KB
/
bstree.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# A Binary Search Tree (BST) Example
#====================================================================================
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
#====================================================================================
class BSTree: # binary serach tree
def __init__(self):
# initializes the root
self.root = None
#--------------------------------------------------------------------------------
# Adds new nodes (Recursive)
def insert_rec(self, tree, value):
if self.root is None:
self.root = Node(value)
return ""
if tree is None:
return Node(value)
elif tree.value == value:
print("Duplicate value already exists in tree!")
return ""
elif value < tree.value:
node = self.insert_rec(tree.left, value)
tree.left = node
return node
else:
node = self.insert_rec(tree.right, value)
tree.right = node
return node
""" Alternative:
if self.root is None:
self.root = Node(value)
return ""
if tree.value == value:
raise Error("Duplicate value already exists in tree!")
elif value < tree.value:
if tree.left is None:
tree.left = Node(value)
else:
self.insert_rec(tree.left, value)
else:
if tree.right is None:
tree.right = Node(value)
else:
self.insert_rec(tree.right, value)
"""
#--------------------------------------------------------------------------------
# Adds new nodes (Non-recursive)
def insert(self, tree, value):
curr = self.root
prev = None
last = ""
while curr.value is not None:
if value < curr.value:
prev = curr
curr = curr.left
last = "L"
elif value > curr.value:
prev = curr
curr = curr.right
last = "R"
else:
raise Error("Duplicate value already exists in tree!")
if last == "L":
prev.left = TreeNode(value)
else:
prev.right = TreeNode(value)
#--------------------------------------------------------------------------------
# Gets the root of the tree
def getRoot(self):
return self.root
#--------------------------------------------------------------------------------
# Looks for a value in the tree (Recursive)
# Returns None if not found else returns the node found
def search_rec(self, tree, target):
if tree is not None:
if target == tree.value:
return tree
elif target < tree.value:
return self.search_rec(tree.left, target)
else:
return self.search_rec(tree.right, target)
#--------------------------------------------------------------------------------
# Looks for a value in the tree (Non-recursive)
# Returns None if not found else returns the node found
def search(self, tree, target):
if self.root is None:
print("Binary tree is empty.")
return None
else:
curr = self.root
found = False
while curr is not None and not found:
if target == curr.value:
found = True
return curr
elif target < curr.value:
curr = curr.left
else:
curr = curr.right
return None if not found
#--------------------------------------------------------------------------------
# Gets the parent of the specified node to search for
def getParent(self, curNode, target, parent):
if curNode == None:
return None
elif curNode.value == target.value:
return parent
else:
if target.value < curNode.value:
return self.getParent(curNode.left, target, curNode)
elif target.value > curNode.value:
return self.getParent(curNode.right, target, curNode)
#--------------------------------------------------------------------------------
# Non-recursive deletion
def delete(self, tree, target):
nodeToDel = self.search(tree, target) # search for the node
if nodeToDel == None:
print (target,'does not exist !')
return
nodeParent = self.getParent(tree, nodeToDel, None) # get parent of the node to be deleted
if (nodeToDel.left and nodeToDel.right) != None: # node to be deleted has two children
# find predecseeor
predNode = nodeToDel.left
while predNode.right != None:
predNode = predNode.right
# set value of the node to be deleted to the value of the predecessor node
nodeToDel.value = predNode.value
# delete the predecessor node
if nodeToDel.left == predNode :
nodeToDel.left = predNode.left
# del predNode # delete the predecessor node
else:
self.delete(nodeToDel.left, predNode.value)
else: # node to be deleted has at most 1 child
# set the parent left/right pointer
if nodeToDel.left == None:
if nodeParent.left == nodeToDel:
nodeParent.left = nodeToDel.right
else:
nodeParent.right = nodeToDel.right
else:
if nodeParent.left == nodeToDel:
nodeParent.left = nodeToDel.left
else:
nodeParent.right = nodeToDel.left
# del nodeToDel # delete the node
#--------------------------------------------------------------------------------
# Gets the size of the tree, i.e. number of nodes
def size(self, tree):
if tree == None:
return 0
else:
return self.size(tree.left) + 1 + self.size(tree.right)
#--------------------------------------------------------------------------------
# Gets the height of the tree
def maxDepth(self, tree):
if tree == None:
return -1
else:
# computes the two depths
lDepth = self.maxDepth(tree.left)
rDepth = self.maxDepth(tree.right)
# returns the appropriate depth
return max(lDepth, rDepth) + 1
#--------------------------------------------------------------------------------
# Returns True if binary tree is height-balanced
def isBalanced (self, tree):
if tree == None:
return True
lh = self.maxDepth(tree.left) # height of left subtree
rh = self.maxDepth(tree.right) # height of right subtree
if abs(lh-rh) <= 1 and \
self.isBalanced(tree.left) and \
self.isBalanced(tree.right):
return True
else:
return False
#--------------------------------------------------------------------------------
# Gets the minimum value
def minValue(self, tree):
# goes down into the left arm and returns the last value
curNode = tree
while curNode.left != None:
curNode = curNode.left
return curNode.value
#--------------------------------------------------------------------------------
# Gets the maximum value
def maxValue(self, tree):
# goes down into the right arm and returns the last value
curr = tree
while curr.right is not None:
curr = curr.right
return curr.value
#--------------------------------------------------------------------------------
# Prints the tree in inOrder -- ascending order
def printTree(self, tree):
if tree is not None:
self.printTree(tree.left)
print(tree.value, end = ' ')
self.printTree(tree.right)
#--------------------------------------------------------------------------------
# Prints the tree in preOrder
def printTree_preOrder(self, tree):
if tree != None:
print (tree.value, end = ' ')
self.printTree_preOrder(tree.left)
self.printTree_preOrder(tree.right)
#--------------------------------------------------------------------------------
# Prints the tree in postOrder
def printTree_postOrder(self, tree):
def printTree(self, tree):
if tree is not None:
self.printTree(tree.left)
self.printTree(tree.right)
print(tree.value, end = ' ')
#--------------------------------------------------------------------------------
# Prints the tree in reverseOrder -- descending order
def printTree_reverseOrder(self, tree):
if tree is not None:
self.printTree_reverseOrder(tree.right)
print(tree.value, end = ' ')
self.printTree_reverseOrder(tree.left)
#====================================================================================
def main():
# Instantiate the binary search tree
tree = BSTree()
# Insert tree nodes to binary search tree
numNodes = int(input("\nEnter number of tree nodes: "))
print ()
for i in range(1, numNodes+1):
value = int(input("Enter value of node %d: " % (i)))
tree.insert(tree.getRoot(), value)
print ()
# Delete a child
value = int(input("Enter the value to be deleted: "))
tree.delete(tree.getRoot(),value)
print ()
# Print the tree in inOrder
print ('InOrder:\t', end = ' ')
tree.printTree(tree.getRoot())
print ()
# Print the tree in preOrder
print ('PreOrder:\t', end = ' ')
tree.printTree_preOrder(tree.getRoot())
print ()
# Print the tree in postOrder
print ('PostOrder:\t', end = ' ')
tree.printTree_postOrder(tree.getRoot())
print ()
# Print the tree in reverseOrder
print ('ReverseOrder:\t', end = ' ')
tree.printTree_reverseOrder(tree.getRoot())
print ()
# Looks for a value in the tree
value = int(input("\nEnter a value to find: "))
if tree.search(tree.getRoot(), value) != None:
print (value,'is found in the tree')
else:
print (value,'is not found in the tree')
# Print maxDepth, maxValue, minValue and the size of the tree
print ('\nMax depth:',tree.maxDepth(tree.getRoot()))
print ('Max value:',tree.maxValue(tree.getRoot()))
print ('Min value:',tree.minValue(tree.getRoot()))
print ('Size:', tree.size(tree.getRoot()))
print ()
# Print whether the tree is balanced
if tree.isBalanced(tree.getRoot()):
print ('Tree is balanced')
else:
print ('Tree is not balanced')
main()