Skip to content
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