Andro Star
Andro Star

Reputation: 11

Getting Wrong ancestor for the right side of the tree

So I was trying to implement LCA using Euler tour and RMQ with Sparse Table in python. My code is working fine, if I insert number from left side of the tree. The code for building the tree is:

The node class has data, left_child and right_child:

class Node:
    def __init__(self, value):
        self.data = value
        self.right_child = None
        self.left_child = None

Then I have a tree class which I used to build the tree:

class Tree:
    content = []
    
    def __init__(self):
        self.root = None
        
    def add_child(self, arr, root, i, n):
        if i < n:
            temp = Node(arr[i])
            root = temp
            
            root.left_child = self.add_child(arr, root.left_child, 2 * i + 1, n)
            root.right_child = self.add_child(arr, root.right_child, 2 * i + 2, n)
            
        return root
    
    def pre_order(self, root):
        
        if root != None:
            Tree.content.append(root.data)
            self.pre_order(root.left_child)
            self.pre_order(root.right_child)
            
        return Tree.content

Finally, I got an LCA class which mainly contains the function for building the sparse table, then do a RMQ on the sparse table, then a function that does the part of the euler tour and finally the function for finding LCA.

class LCA:
    
    def __init__(self, root, length):
        self.pre_process_array = [[0] * (math.floor(math.log2(length) + 2)) for _ in range((length * 2) - 1)]
        self.euler = [0] * (length * 2 - 1)
        self.height = [0] * (length * 2 - 1)
        self.index = [-1  for _ in range(length + 1)]
        self.tour = 0
        
        self.euler_tour(root, 0)
        self.build_sparse_table(self.height)
        
        print(self.pre_process_array)
        
    def build_sparse_table(self, height_array):
        for i in range(len(height_array)):
            self.pre_process_array[i][0] = height_array[i]
            
        j = 1
        
        while (1 << j) <= len(height_array):
            
            i = 0
            while (i + (1 << j) - 1) < len(height_array):
                
                if self.pre_process_array[i][j - 1] < self.pre_process_array[i + (1 << (j - 1))][j-1]:
                    self.pre_process_array[i][j] = self.pre_process_array[i][j - 1]
                else:
                    self.pre_process_array[i][j] = self.pre_process_array[i + (1 << (j - 1))][j - 1]
                    
                i += 1
            
            j += 1
            
    def rmq(self, l, h):
        j = int(math.log2(h - l + 1))
        
        if self.pre_process_array[l][j] <= self.pre_process_array[h - (1 << j) + 1][j]:
            return self.pre_process_array[l][j]
        else:
            return self.pre_process_array[h - (1 << j) + 1][j]
        
    def euler_tour(self, root, level):
        if root is not None:

            self.euler[self.tour] = root.data
            self.height[self.tour] = level
            self.tour += 1
            
            if self.index[root.data] == -1:
                self.index[root.data] = self.tour - 1
                
            if root.left_child is not None:
                self.euler_tour(root.left_child, level + 1)
                self.euler[self.tour] = root.data
                self.height[self.tour] = level
                self.tour += 1
                
            if root.right_child is not None:
                self.euler_tour(root.right_child, level + 1)
                self.euler[self.tour] = root.data
                self.height[self.tour] = level
                self.tour += 1
            
    def find_LCA(self, val1, val2):
        if val1 >= len(self.index) or val2 >= len(self.index) or self.index[val1] == -1 or self.index[val2] == -1:
            return -1
        
        if self.index[val1] > self.index[val2]:
            return self.euler[self.rmq(self.index[val2], self.index[val1])]
        elif self.index[val2] > self.index[val1]:
            return self.euler[self.rmq(self.index[val1], self.index[val2])]

And my driver code is as follow:

tree_data = [1,2,3,4,5,6,7,8,9]
length = len(tree_data)
         
tree = Tree()
root = tree.root

tree.root = tree.add_child(tree_data, root, 0, length)
l = LCA(tree.root, length)

print(l.find_LCA(6, 3))

so, my tree should something look like:

                               1
                             /   \
                            2     3
                           / \   / \
                          4   5  6  7
                         / \
                        8   9  

Now, if I try to find the LCA(8, 9) or LCA(4, 3), I get the correct output but whenever I try to give LCA(6, 7) or LCA(3, 7), It always keeps returning 2 as the answer where it should return 3 and 3 respectively.

I don't have any idea where is the mistake as, from my side it looks pretty fine.

Upvotes: 1

Views: 48

Answers (0)

Related Questions