-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathbinary-search-tree.py
More file actions
219 lines (178 loc) · 5.7 KB
/
binary-search-tree.py
File metadata and controls
219 lines (178 loc) · 5.7 KB
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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = "David S. Batista"
__email__ = "dsbatista@inesc-id.pt"
# TODO: delete
class Node:
def __init__(self, _value):
self.left_child = None
self.right_child = None
self.value = _value
def insert(self, value):
if self.value is not None:
if value > self.value:
if self.right_child is None:
self.right_child = Node(value)
else:
self.right_child.insert(value)
elif value < self.value:
if self.left_child is None:
self.left_child = Node(value)
else:
self.left_child.insert(value)
else:
self.value = value
# In-Order Tree Walk
def in_order_tree_walk(node):
if node.left_child:
in_order_tree_walk(node.left_child)
print node.value,
if node.right_child:
in_order_tree_walk(node.right_child)
# Pre-Order Tree Walk (i.e., Deep-first Search - DFS)
def pre_order_tree_walk(node):
print node.value,
if node.left_child:
in_order_tree_walk(node.left_child)
if node.right_child:
in_order_tree_walk(node.right_child)
# Post-Order Tree Walk
def post_order_tree_walk(node):
if node:
post_order_tree_walk(node.left_child)
post_order_tree_walk(node.right_child)
print node.value,
# Maximum element in the Tree
def max_node(node):
while node.right_child:
node = node.right_child
return node.value
# Minimum element in the Tree
def min_node(node):
while node.left_child:
node = node.left_child
return node.value
# Tree-Search
def search(node, k):
if k == node.value:
return node
elif k < node.value:
if node.left_child:
return search(node.left_child, k)
else:
if node.right_child:
return search(node.right_child, k)
# Breadth-first Search - BFS
def print_bfs(root):
this_level = [root]
while this_level:
next_level = list()
for n in this_level:
print n.value,
if n.left_child:
next_level.append(n.left_child)
if n.right_child:
next_level.append(n.right_child)
this_level = next_level
print
# Validate BST
def in_order_traversal_validation(node, previous):
"""
While doing In-Order traversal, we can keep track of previously
visited node. If the value of the currently visited node is less than
the previous value, then tree is not BST.
"""
if node.left_child:
in_order_traversal_validation(node.left_child, node)
if previous:
print node.value, previous.value
if node.value < previous.value:
return False
else:
return True
if node.right_child:
in_order_traversal_validation(node, node.right_child)
# Lowest Common Ancestor
def lowest_common_ancestor(root, n1, n2):
"""
Method 1 (By Storing root to n1 and root to n2 paths):
Following is simple O(n) algorithm to find LCA of n1 and n2.
1) Find path from root to n1 and store it in a vector or array.
2) Find path from root to n2 and store it in another vector or array.
3) Traverse both paths till the values in arrays are same.
Return the common element just before the mismatch.
"""
p1 = []
p2 = []
find_path(root, n1, p1)
find_path(root, n2, p2)
print p1
print p2
if n1 in p2:
return n1
if n2 in p1:
return n2
x = -1
y = -1
last_equal = -1
while x == y:
if len(p1) == 1:
return p1[0]
elif len(p2) == 1:
return p2[0]
else:
last_equal = x
x = p1.pop(0)
y = p2.pop(0)
return last_equal
# Find path between a node value
def find_path(node, k, path):
if k == node.value:
return path
elif k < node.value:
path.append(node.value)
find_path(node.left_child, k, path)
else:
path.append(node.value)
find_path(node.right_child, k, path)
# Lowest Common Ancestor: simpler and recursive version
def lca(root, n1, n2):
"""
We can solve this problem using BST properties. We can recursively
traverse the BST from root. The main idea of the solution is,
while traversing from top to bottom, the first node n we encounter with
value between n1 and n2, i.e., n1 < n < n2 or same as one of the n1 or n2,
is LCA of n1 and n2 (assuming that n1 < n2).
So just recursively traverse the BST in, if node’s value is greater
than both n1 and n2 then our LCA lies in left side of the node,
if it’s is smaller than both n1 and n2, then LCA lies on right side.
Otherwise root is LCA (assuming that both n1 and n2 are present in BST)
"""
# Base Case
if root is None:
return None
# If both n1 and n2 are smaller than root, then LCA lies on the left
if root.value > n1 and root.value > n2:
return lca(root.left_child, n1, n2)
# If both n1 and n2 are greater than root, then LCA on the right
if root.value < n1 and root.value < n2:
return lca(root.right_child, n1, n2)
return root
def main():
arr = [3, 1, 6, 4, 7, 10, 14, 13]
root = Node(8)
for i in arr:
root.insert(i)
print "lca(6,3):", lca(root, 6, 3)
print "lca(6,14):", lca(6, 14)
x = lowest_common_ancestor(root, 4, 13)
print "lca(4,13):", x
print lca(root, 10, 8).value
x = lowest_common_ancestor(root, 4, 1)
print "lca(4,1):", x
print lca(root, 4, 1).value
x = lowest_common_ancestor(root, 4, 3)
print "lca(4,3):", x
print lca(root, 4, 3).value
if __name__ == "__main__":
main()