Skip to content

Added LCA and tests #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Mar 5, 2020
101 changes: 101 additions & 0 deletions pydatastructs/trees/binary_trees.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,107 @@ def rank(self, x):
walk = p
return r

def _simple_path(self, key, root, path):
"""
Utility funtion to find the simple path between root and node.
"""
if root is None:
return False
path.append(root)
if self.tree[root].key == key:
return True

if self._simple_path(key, self.tree[root].left, path) or \
self._simple_path(key, self.tree[root].right, path):
path.append(root)
return True

path.pop()
return False

def simple_path(self, key):
path = []
self._simple_path(key, self.root_idx, path)
return path

def lowest_common_ancestor(self, j, k, algorithm=1):

"""
Computes the lowest common ancestor of two nodes.

Parameters
==========

j: Node.key
key of first node
k: Node.key
key of second node
algorithm: int
The algorithm to be used for computing the
lowest common ancestor.
Optional, by default uses algorithm 1.

1 -> Determines the lowest common ancestor by finding
the first intersection of the paths from v and w
to the root.

2 -> Modifed version of the algorithm given in the
following publication,
D. Harel. A linear time algorithm for the
lowest common ancestors problem. In 21s
Annual Symposium On Foundations of
Computer Science, pages 308-319, 1980.

Returns
=======

int
The index of the lowest common ancestor in the tree.
if both the nodes are present in the tree.
None
In all other cases.

References
==========

.. [1] https://en.wikipedia.org/wiki/Lowest_common_ancestor

.. [2] https://pdfs.semanticscholar.org/e75b/386cc554214aa0ebd6bd6dbdd0e490da3739.pdf

"""
if algorithm == 1:
curr_root = self.root_idx
u, v = self.search(j), self.search(k)
if (u is None) or (v is None):
return None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A value error would have been better to let the user know that they are searching for garbage values.

u_left = self.comparator(self.tree[u].key, self.tree[curr_root].key)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

v_left = self.comparator(self.tree[v].key, self.tree[curr_root].key)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

while not (u_left ^ v_left):
if u_left and v_left:
curr_root = self.tree[curr_root].left
else:
curr_root = self.tree[curr_root].right
if curr_root == u or curr_root == v:
return curr_root
u_left = self.comparator(self.tree[u].key, self.tree[curr_root].key)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please split this into two lines. Doesn't look clean.

v_left = self.comparator(self.tree[v].key, self.tree[curr_root].key)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

return curr_root
else:
root = self.root_idx
path1 = self.simple_path(j)
path2 = self.simple_path(k)
if not path1 or not path2:
return None

n, m = len(path1), len(path2)
i = j = 0
while i < n and j < m:
if path1[i] != path2[j]:
return path1[i - 1]
i += 1
j += 1
return None

class AVLTree(BinarySearchTree):
"""
Represents AVL trees.
Expand Down
7 changes: 7 additions & 0 deletions pydatastructs/trees/tests/test_binary_trees.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ def test_BinarySearchTree():
assert b.delete(-10) is True
assert b.delete(-3) is True
assert b.delete(-13) is None
bl = BST()
nodes = [50, 30, 90, 70, 100, 60, 80, 55]
for node in nodes:
bl.insert(node, node)
assert bl.tree[bl.lowest_common_ancestor(80, 55, 2)].key == 70
assert bl.tree[bl.lowest_common_ancestor(60, 70, 2)].key == 70
assert bl.lowest_common_ancestor(-3, 4) is None
raises(ValueError, lambda: BST(root_data=6))

def test_BinaryTreeTraversal():
Expand Down