Queries to find distance between two nodes of a Binary tree – O(logn) method

Given a binary tree, the task is to find the distance between two keys in a binary tree, no parent pointers are given. Distance between two nodes is the minimum number of edges to be traversed to reach one node from other.
This problem has been already discussed in previous post but it uses three traversals of the Binary tree, one for finding Lowest Common Ancestor(LCA) of two nodes(let A and B) and then two traversals for finding distance between LCA and A and LCA and B which has O(n) time complexity. In this post, a method will be discussed that requires the O(log(n)) time to find LCA of two nodes.



The distance between two nodes can be obtained in terms of lowest common ancestor. Following is the formula.

Dist(n1, n2) = Dist(root, n1) + Dist(root, n2) - 2*Dist(root, lca) 
'n1' and 'n2' are the two given keys
'root' is root of given Binary Tree.
'lca' is lowest common ancestor of n1 and n2
Dist(n1, n2) is the distance between n1 and n2.

Above formula can also be written as:

Dist(n1, n2) = Level[n1] + Level[n2] - 2*Level[lca] 

This problem can be breakdown into:

  1. Finding levels of each node
  2. Finding the Euler tour of binary tree
  3. Building segment tree for LCA,

These steps are explained below :



  1. Find the levels of each node by applying level order traversal.
  2. Find the LCA of two nodes in binary tree in O(logn) by Storing Euler tour of Binary tree in array and computing two other arrays with the help of levels of each node and Euler tour.
    These steps are shown below:

    (I) First, find Euler Tour of binary tree.

    Euler tour of binary tree in example

    (II) Then, store levels of each node in Euler array.

    (III) Then, store First occurrences of all nodes of binary tree in Euler array. H stores the indices of nodes from Euler array, so that range of query for finding minimum can be minimized and their by further optimizing the query time.

  3. Then build segment tree on L array and take the low and high values from H array that will give us the first occurrences of say Two nodes(A and B) . Then, <strong>we query segment tree to find the minimum value say X in range (H[A] to H[B]). Then we use the index of value X as index to Euler array to get LCA, i.e. Euler[index(X)].

    Let, A = 8 and B = 5.
    (I) H[8] = 1 and H[5] =2
    (II) Querying on Segment tree, we get min value in L array between 1 and 2 as X=0, index=7
    (III) Then, LCA= Euler[7], i.e LCA = 1.

  4. Finally, we apply distance formula discussed above to get distance between two nodes.
filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to find distance between
// two nodes for multiple queries
#include <bits/stdc++.h>
#define MAX 100001
using namespace std;
  
/* A tree node structure */
struct Node {
    int data;
    struct Node* left;
    struct Node* right;
};
  
/* Utility function to create a new Binary Tree node */
struct Node* newNode(int data)
{
    struct Node* temp = new struct Node;
    temp->data = data;
    temp->left = temp->right = NULL;
    return temp;
}
  
// Array to store level of each node
int level[MAX];
  
// Utility Function to store level of all nodes
void FindLevels(struct Node* root)
{
    if (!root)
        return;
  
    // queue to hold tree node with level
    queue<pair<struct Node*, int> > q;
  
    // let root node be at level 0
    q.push({ root, 0 });
  
    pair<struct Node*, int> p;
  
    // Do level Order Traversal of tree
    while (!q.empty()) {
        p = q.front();
        q.pop();
  
        // Node p.first is on level p.second
        level[p.first->data] = p.second;
  
        // If left child exits, put it in queue
        // with current_level +1
        if (p.first->left)
            q.push({ p.first->left, p.second + 1 });
  
        // If right child exists, put it in queue
        // with current_level +1
        if (p.first->right)
            q.push({ p.first->right, p.second + 1 });
    }
}
  
// Stores Euler Tour
int Euler[MAX];
  
// index in Euler array
int idx = 0;
  
// Find Euler Tour
void eulerTree(struct Node* root)
{
  
    // store current node's data
    Euler[++idx] = root->data;
  
    // If left node exists
    if (root->left) {
  
        // traverse left subtree
        eulerTree(root->left);
  
        // store parent node's data
        Euler[++idx] = root->data;
    }
  
    // If right node exists
    if (root->right) {
        // traverse right subtree
        eulerTree(root->right);
  
        // store parent node's data
        Euler[++idx] = root->data;
    }
}
  
// checks for visited nodes
int vis[MAX];
  
// Stores level of Euler Tour
int L[MAX];
  
// Stores indices of first occurrence
// of nodes in Euler tour
int H[MAX];
  
// Preprocessing Euler Tour for finding LCA
void preprocessEuler(int size)
{
    for (int i = 1; i <= size; i++) {
        L[i] = level[Euler[i]];
  
        // If node is not visited before
        if (vis[Euler[i]] == 0) {
            // Add to first occurrence
            H[Euler[i]] = i;
  
            // Mark it visited
            vis[Euler[i]] = 1;
        }
    }
}
  
// Stores values and positions
pair<int, int> seg[4 * MAX];
  
// Utility function to find minimum of
// pair type values
pair<int, int> min(pair<int, int> a,
                   pair<int, int> b)
{
    if (a.first <= b.first)
        return a;
    else
        return b;
}
  
// Utility function to build segment tree
pair<int, int> buildSegTree(int low, int high, int pos)
{
    if (low == high) {
        seg[pos].first = L[low];
        seg[pos].second = low;
        return seg[pos];
    }
    int mid = low + (high - low) / 2;
    buildSegTree(low, mid, 2 * pos);
    buildSegTree(mid + 1, high, 2 * pos + 1);
  
    seg[pos] = min(seg[2 * pos], seg[2 * pos + 1]);
}
  
// Utility function to find LCA
pair<int, int> LCA(int qlow, int qhigh, int low,
                   int high, int pos)
{
    if (qlow <= low && qhigh >= high)
        return seg[pos];
  
    if (qlow > high || qhigh < low)
        return { INT_MAX, 0 };
  
    int mid = low + (high - low) / 2;
  
    return min(LCA(qlow, qhigh, low, mid, 2 * pos),
               LCA(qlow, qhigh, mid + 1, high, 2 * pos + 1));
}
  
// Function to return distance between
// two nodes n1 and n2
int findDistance(int n1, int n2, int size)
{
    // Maintain original Values
    int prevn1 = n1, prevn2 = n2;
  
    // Get First Occurrence of n1
    n1 = H[n1];
  
    // Get First Occurrence of n2
    n2 = H[n2];
  
    // Swap if low > high
    if (n2 < n1)
        swap(n1, n2);
  
    // Get position of minimum value
    int lca = LCA(n1, n2, 1, size, 1).second;
  
    // Extract value out of Euler tour
    lca = Euler[lca];
  
    // return calculated distance
    return level[prevn1] + level[prevn2] - 2 * level[lca];
}
  
void preProcessing(Node* root, int N)
{
    // Build Tree
    eulerTree(root);
  
    // Store Levels
    FindLevels(root);
  
    // Find L and H array
    preprocessEuler(2 * N - 1);
  
    // Build segment Tree
    buildSegTree(1, 2 * N - 1, 1);
}
  
/* Driver function to test above functions */
int main()
{
    int N = 8; // Number of nodes
  
    /* Constructing tree given in the above figure */
    Node* root = newNode(1);
    root->left = newNode(2);
    root->right = newNode(3);
    root->left->left = newNode(4);
    root->left->right = newNode(5);
    root->right->left = newNode(6);
    root->right->right = newNode(7);
    root->right->left->right = newNode(8);
  
    // Function to do all preprocessing
    preProcessing(root, N);
  
    cout << "Dist(4, 5) = " << findDistance(4, 5, 2 * N - 1) << "\n";
    cout << "Dist(4, 6) = " << findDistance(4, 6, 2 * N - 1) << "\n";
    cout << "Dist(3, 4) = " << findDistance(3, 4, 2 * N - 1) << "\n";
    cout << "Dist(2, 4) = " << findDistance(2, 4, 2 * N - 1) << "\n";
    cout << "Dist(8, 5) = " << findDistance(8, 5, 2 * N - 1) << "\n";
  
    return 0;
}

chevron_right


Output:

Dist(4, 5) = 2
Dist(4, 6) = 4
Dist(3, 4) = 3
Dist(2, 4) = 1
Dist(8, 5) = 5

Time Complexity: O(Log N)
Space Complexity: O(N)

Queries to find distance between two nodes of a Binary tree – O(1) method



My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.