Open In App

Jump Pointer Algorithm

Improve
Improve
Like Article
Like
Save
Share
Report

The Jump pointer algorithm is a design technique for parallel algorithms that operate on pointer structures, such as arrays or linked list. This algorithm is normally used to determine the root of the forest of a rooted tree.

In the jump pointer algorithm, we pre-process a tree so that one can able to answer the queries to find any parent of any node in the tree in time complexity of O(log n)

The jump pointer algorithm associates up to log2n pointers to each vertex of the tree. These pointers are called jump pointers because they jump up the tree towards the root node of the tree. For any node of the processing tree, the algorithm stores an array of length l jumpers where l = log2(depth(v)). The ith element of this array points to the 2ith parent of the node v. This data structure helps us to jump halfway up the tree from any given node. When the algorithm is asked to process a query to find any parent of any node in the tree, we repeatedly jump up the tree using these pointers. The number of jumps will be at most log n and therefore any problem to find the parent of any node in the tree can be answered in O(log n) time complexity. 
In jump pointer, there is a pointer from node N to N’s j-th parent, for 
j = 1, 2, 4, 8, …, and so on. So we store 2ith parent of each node.

The jump pointer algorithm basically works on the approach of dynamic programming where we use the pre-computed result to find the next result. By doing some simple calculations we can compute the mathematical formula that for any node k, 2jth parent of k is equal to 2j-1th parent of 2j-1th parent of k

The brief explanation of this formula is given below in the algorithm section.

The most common use of this algorithm is to solve the queries in which we need to find the ancestor of any node in O(log n) time complexity. 

Graph to implement Jump Pointer Algorithm: 

Representation of jump array that stores 2^i th parent of all nodes: 

Examples: 

Input: 0th parent of node 2 
Output: 0th parent of node 2 is = 2

Input: 2nd parent of node 4
Output: 2nd parent of node 4 is = 2

Input: 3rd parent of node 8 
Output: 3rd parent of node 8 is = 1

Algorithm : 

Here is the algorithm to implement the jump pointer algorithm to find any parent of any node in the graph. We determine the jump matrix using dynamic programming. Here, we denote the root node as R and initially assume the parent of the root node as 0 which means there is no parent of this node

Now looking at the graph and the array is shown in the above diagram we can easily understand the above formula to determine the 2ith parent of each node. If we look at the node with value 8 we can see that its 20th parent is 10, now to find its 21th parent we see that it’s 21th parent is 20th parent of the node with value 10 and here 10 is 20th parent of 8 it means 21th parent of node 8 is 20th parent of 20th parent of node 8. Similarly, we can also see that 22th parent of node 8 is 5 which is 21th parent of 21th parent of node 8 i.e 21th parent of node with value 9

Thus in this way we can compute the array of jump pointers for all the nodes to store their 2ith parents.

Below is the pseudo code to calculate the jump pointer matrix that store 2ith parent of all the nodes in the tree. 

jump[k][j] =   it points 2^jth parent of k    
             =  2^j-1th parent of (2^j-1th parent of k)       
             =  jump[jump[i][j-1][j-1] 

Implementation: Below is the code to implement the above algorithm to find any parent of any node in O( logn ) time complexity.

C++




// C++ program to implement Jump pointer algorithm
#include <bits/stdc++.h>
using namespace std;
 
int R = 0;
// n -> it represent total number of nodes
// len -> it is the maximum length of array
// to hold parent of each node.
// In worst case, the highest value of
// parent a node can have is n-1.
// 2 ^ len <= n-1
// len = O(log2n)
int getLen(int n)
{
    int len = (int)(log(n) / log(2)) + 1;
    return len;
}
 
// jump represent 2D matrix to hold parent of node in jump matrix
// here we pass reference of 2D matrix so that the change made
// occur directly to the original matrix
// len is same as defined above
// n is total nodes in graph
void set_jump_pointer(vector<vector<int> >& jump,
                      vector<int> node, int len, int n)
{
    for (int j = 1; j <= len; j++)
        for (int i = 0; i < n; i++)
            jump[ node[i] ][j] = jump[jump[node[i] ][j - 1] ][j - 1];
}
 
// c -> it represent child
// p -> it represent parent
// i -> it represent node number
// p=0 means the node is root node
// here also we pass reference of 2D matrix
// and depth vector so that the change made
// occur directly to the original matrix and original vector
void constructGraph(vector<vector<int> >& jump,
                    vector<int>& node, vector<int>& isNode, int c, int p, int i)
{
    // enter the node in node array
    // it stores all the nodes in the graph
    node[i] = c;
 
    // to confirm that no child node have 2 parents
    if (isNode == 0) {
        isNode = 1;
        // make parent of x as y
        jump[0] = p;
    }
    return;
}
 
// function to jump to Lth parent of any node
void jumpPointer(vector<vector<int> >& jump,
                 vector<int> isNode, int x, int L, int n)
{
    int j = 0, curr = x, k = L;
 
    // to check if node is present in graph or not
    if (x > n || isNode[x] == 0) {
        cout << "Node is not present in graph " << endl;
        return;
    }
 
    // in this loop we decrease the value of L by L/2 and
    // increment j by 1 after each iteration, and check for set bit
    // if we get set bit then we update x with jth parent of x
    // as L becomes less than or equal to zero means
    // we have jumped to Lth parent of node x
    while (L > 0) {
        // to check if last bit is 1 or not
        if (L & 1)
            x = jump[x][j];
 
        // use of shift operator to make
        // L = L/2 after every iteration
        L = L >> 1;
        j++;
    }
 
    cout << k << "th parent of node " << curr
                   << " is = " << x << endl;
 
    return;
}
 
// Driver code
int main()
{
    // n represent number of nodes
    int n = 11;
 
    // function to calculate len
    // len -> it is the maximum length of
    // array to hold parent of each node.
    int len = getLen(n);
   
    // initialization of parent matrix
    vector<vector<int> > jump(n+1, vector<int>(len+1));
 
    // node array is used to store all nodes
    vector<int> node(n+1);
 
    // isNode is an array to check whether
    // a node is present in graph or not
    vector<int> isNode(n+1,0);
 
    // R stores root node
    R = 2;
 
    // construction of graph
    // here 0 represent that the node is root node
    constructGraph(jump, node, isNode, 2, 0, 0);
    constructGraph(jump, node, isNode, 5, 2, 1);
    constructGraph(jump, node, isNode, 3, 5, 2);
    constructGraph(jump, node, isNode, 4, 5, 3);
    constructGraph(jump, node, isNode, 1, 5, 4);
    constructGraph(jump, node, isNode, 7, 1, 5);
    constructGraph(jump, node, isNode, 9, 1, 6);
    constructGraph(jump, node, isNode, 10, 9, 7);
    constructGraph(jump, node, isNode, 11, 10, 8);
    constructGraph(jump, node, isNode, 6, 10, 9);
    constructGraph(jump, node, isNode, 8, 10, 10);
 
    // function to pre compute jump matrix
    set_jump_pointer(jump, node, len, n);
 
    // query to jump to parent using jump pointers
    // query to jump to 1st parent of node 2
    jumpPointer(jump, isNode, 2, 0, n);
 
    // query to jump to 2nd parent of node 4
    jumpPointer(jump, isNode, 4, 2, n);
 
    // query to jump to 3rd parent of node 8
    jumpPointer(jump, isNode, 8, 3, n);
 
    // query to jump to 5th parent of node 20
    jumpPointer(jump, isNode, 20, 5, n);
 
    return 0;
}


Python3




# Python3 program to implement
# Jump pointer algorithm
import math
 
# Initialization of parent matrix
# suppose max range of a node is
# up to 1000 if there are 1000 nodes
#  than also length of jump matrix
# will not exceed 10
jump = [[0 for j in range(10)]
           for i in range(1000)]
  
# Node array is used to store all nodes
node = [0 for i in range(1000)]
  
# isNode is an array to check whether
# a node is present in graph or not
isNode = [0 for i in range(1000)]
 
# n -> it represent total number of nodes
# len -> it is the maximum length of array
# to hold parent of each node.
# In worst case, the highest value of
# parent a node can have is n-1.
# 2 ^ len <= n-1
# len = O(log2n)
def getLen(n):
 
    len = int((math.log(n)) //
              (math.log(2))) + 1
    return len
 
# jump represent 2D matrix to hold parent
# of node in jump matrix here we pass
# reference of 2D matrix so that the
# change made occur directly to the
# original matrix len is same as
# defined above n is total nodes
# in graph
def set_jump_pointer(len, n):
     
    global jump, node
    for j in range(1,len + 1):
        for i in range(0, n):
            jump[node[i]][j] = jump[jump[node[i]][j - 1]][j - 1]
 
# c -> it represent child
# p -> it represent parent
# i -> it represent node number
# p=0 means the node is root node
# here also we pass reference of
# 2D matrix and depth vector so
# that the change made occur
# directly to the original matrix
# and original vector
def constructGraph(c, p, i):
     
    global jump, node, isNode
     
    # Enter the node in node array
    # it stores all the nodes in the graph
    node[i] = c
  
    # To confirm that no child node
    # have 2 parents
    if (isNode == 0):
        isNode = 1
         
        # Make parent of x as y
        jump[0] = p
     
    return
 
# function to jump to Lth parent
# of any node
def jumpPointer(x, L):
     
    j = 0
    n = x
    k = L
     
    global jump, isNode
     
    # To check if node is present in
    # graph or not
    if (isNode[x] == 0):
        print("Node is not present in graph ")
        return
         
    # In this loop we decrease the value
    # of L by L/2 and increment j by 1
    # after each iteration, and check
    # for set bit if we get set bit
    # then we update x with jth parent
    # of x as L becomes less than or
    # equal to zero means we have
    # jumped to Lth parent of node x
    while (L > 0):
         
        # To check if last bit is 1 or not
        if ((L & 1)!=0):
            x = jump[x][j]
  
        # Use of shift operator to make
        # L = L/2 after every iteration
        L = L >> 1
        j += 1
         
    print(str(k) + "th parent of node " +
          str(n) + " is = " + str(x))  
  
    return
 
# Driver code
if __name__=="__main__":
     
    # n represent number of nodes
    n = 11
  
    # Function to calculate len
    # len -> it is the maximum length of
    # array to hold parent of each node.
    len = getLen(n)
  
    # R stores root node
    R = 2
  
    # Construction of graph
    # here 0 represent that
    # the node is root node
    constructGraph(2, 0, 0)
    constructGraph(5, 2, 1)
    constructGraph(3, 5, 2)
    constructGraph(4, 5, 3)
    constructGraph(1, 5, 4)
    constructGraph(7, 1, 5)
    constructGraph(9, 1, 6)
    constructGraph(10, 9, 7)
    constructGraph(11, 10, 8)
    constructGraph(6, 10, 9)
    constructGraph(8, 10, 10)
  
    # Function to pre compute jump matrix
    set_jump_pointer(len, n)
  
    # Query to jump to parent using jump pointers
    # query to jump to 1st parent of node 2
    jumpPointer(2, 0)
  
    # Query to jump to 2nd parent of node 4
    jumpPointer(4, 2)
  
    # Query to jump to 3rd parent of node 8
    jumpPointer(8, 3)
  
    # Query to jump to 5th parent of node 20
    jumpPointer(20, 5)
 
# This code is contributed by rutvik_56


Javascript




//Js code for the above approach
// R is global variable to store root node
let R = 0;
 
// n represents total number of nodes
// len represents the maximum length of array to hold parent of each node
// In worst case, the highest value of parent a node can have is n-1
// 2 ^ len <= n-1
// len = O(log2n)
function getLen(n) {
    let len = Math.ceil(Math.log(n) / Math.log(2)) + 1;
    return len;
}
 
// jump represents 2D matrix to hold parent of node in jump matrix
// here we pass reference of 2D matrix so that the change made
// occur directly to the original matrix
// len is same as defined above
// n is total nodes in graph
function set_jump_pointer(jump, node, len, n) {
    for (let j = 1; j <= len; j++) {
        for (let i = 0; i < n; i++) {
            jump[node[i]][j] = jump[jump[node[i]][j - 1]][j - 1];
        }
    }
}
 
// c represents child
// p represents parent
// i represents node number
// p=0 means the node is root node
// here also we pass reference of 2D matrix
// and depth vector so that the change made
// occur directly to the original matrix and original vector
function constructGraph(jump, node, isNode, c, p, i) {
    // enter the node in node array
    // it stores all the nodes in the graph
    node[i] = c;
 
    // to confirm that no child node have 2 parents
    if (isNode === 0) {
        isNode = 1;
        // make parent of x as y
        jump[0] = p;
    }
}
 
// function to jump to Lth parent of any node
function jumpPointer(jump, isNode, x, L, n) {
    let j = 0, curr = x, k = L;
 
    // to check if node is present in graph or not
    if (x > n || isNode[x] === 0) {
        console.log("Node is not present in graph ");
        return;
    }
 
    // in this loop we decrease the value of L by L/2 and
    // increment j by 1 after each iteration, and check for set bit
    // if we get set bit then we update x with jth parent of x
    // as L becomes less than or equal to zero means
    // we have jumped to Lth parent of node x
    while (L > 0) {
        // to check if last bit is 1 or not
        if (L & 1)
            x = jump[x][j];
 
        // use of shift operator to make
        // L = L/2 after every iteration
        L = L >> 1;
        j++;
    }
 
    console.log(k + "th parent of node " + curr
                   + " is = " + x);
 
    return;
}
 
// Driver code
 
    // n represent number of nodes
    let n = 11;
 
    // function to calculate len
    // len -> it is the maximum length of
    // array to hold parent of each node.
    let len = getLen(n);
   
    // initialization of parent matrix
    let jump = new Array(n+1).fill(null).map(() => new Array(len+1).fill(0));
 
    // node array is used to store all nodes
    let node = new Array(n+1).fill(0);
 
    // isNode is an array to check whether
    // a node is present in graph or not
    let isNode = new Array(n+1).fill(0);
 
    // R stores root node
     R = 2;
 
    // construction of graph
    // here 0 represent that the node is root node
    constructGraph(jump, node, isNode, 2, 0, 0);
    constructGraph(jump, node, isNode, 5, 2, 1);
    constructGraph(jump, node, isNode, 3, 5, 2);
    constructGraph(jump, node, isNode, 4, 5, 3);
    constructGraph(jump, node, isNode, 1, 5, 4);
    constructGraph(jump, node, isNode, 7, 1, 5);
    constructGraph(jump, node, isNode, 9, 1, 6);
    constructGraph(jump, node, isNode, 10, 9, 7);
    constructGraph(jump, node, isNode, 11, 10, 8);
    constructGraph(jump, node, isNode, 6, 10, 9);
    constructGraph(jump, node, isNode, 8, 10, 10);
 
    // function to pre compute jump matrix
    set_jump_pointer(jump, node, len, n);
 
    // query to jump to parent using jump pointers
    // query to jump to 1st parent of node 2
    jumpPointer(jump, isNode, 2, 0, n);
 
    // query to jump to 2nd parent of node 4
    jumpPointer(jump, isNode, 4, 2, n);
 
    // query to jump to 3rd parent of node 8
    jumpPointer(jump, isNode, 8, 3, n);
 
    // query to jump to 5th parent of node 20
    jumpPointer(jump, isNode, 20, 5, n);
 
// This code is contributed by lokeshpotta20.


C#




using System;
using System.Collections.Generic;
 
public class GFG {
public static int R = 0;
public static int getLen(int n) {
    int len = (int)(Math.Log(n) / Math.Log(2)) + 1;
    return len;
}
 
public static void set_jump_pointer(List<List<int>> jump, List<int> node, int len, int n) {
    for (int j = 1; j <= len; j++) {
        for (int i = 0; i < n; i++) {
            jump[node[i]][j] = jump[jump[node[i]][j - 1]][j - 1];
        }
    }
}
 
public static void constructGraph(List<List<int>> jump, List<int> node, List<int> isNode, int c, int p, int i) {
    node[i] = c;
    if (isNode == 0) {
        isNode = 1;
        jump[0] = p;
    }
    return;
}
 
public static void jumpPointer(List<List<int>> jump, List<int> isNode, int x, int L, int n) {
    int j = 0, curr = x, k = L;
    if (x > n || isNode[x] == 0) {
        Console.WriteLine("Node is not present in graph ");
        return;
    }
    while (L > 0) {
        if ((L & 1) == 1)
            x = jump[x][j];
        L = L >> 1;
        j++;
    }
    Console.WriteLine(k + "th parent of node " + curr + " is = " + x);
    return;
}
 
public static void Main() {
    int n = 11;
    int len = getLen(n);
    List<List<int>> jump = new List<List<int>>();
    for (int i = 0; i <= n; i++) {
        jump.Add(new List<int>());
        for (int j = 0; j <= len; j++) {
            jump[i].Add(0);
        }
    }
    List<int> node = new List<int>();
    for (int i = 0; i <= n; i++) {
        node.Add(0);
    }
    List<int> isNode = new List<int>();
    for (int i = 0; i <= n; i++) {
        isNode.Add(0);
    }
    R = 2;
    constructGraph(jump, node, isNode, 2, 0, 0);
    constructGraph(jump, node, isNode, 5, 2, 1);
    constructGraph(jump, node, isNode, 3, 5, 2);
    constructGraph(jump, node, isNode, 4, 5, 3);
    constructGraph(jump, node, isNode, 1, 5, 4);
    constructGraph(jump, node, isNode, 7, 1, 5);
    constructGraph(jump, node, isNode, 9, 1, 6);
    constructGraph(jump, node, isNode, 10, 9, 7);
    constructGraph(jump, node, isNode, 11, 10, 8);
    constructGraph(jump, node, isNode, 6, 10, 9);
    constructGraph(jump, node, isNode, 8, 10, 10);
// function to pre compute jump matrix
    set_jump_pointer(jump, node, len, n);
 
    // query to jump to parent using jump pointers
    // query to jump to 1st parent of node 2
    jumpPointer(jump, isNode, 2, 0, n);
 
    // query to jump to 2nd parent of node 4
    jumpPointer(jump, isNode, 4, 2, n);
 
    // query to jump to 3rd parent of node 8
    jumpPointer(jump, isNode, 8, 3, n);
 
    // query to jump to 5th parent of node 20
    jumpPointer(jump, isNode, 20, 5, n);
 
}}


Java




import java.util.*;
 
public class Main {
 
    static int R = 0;
 
    // n -> it represent total number of nodes
    // len -> it is the maximum length of array
    // to hold parent of each node.
    // In worst case, the highest value of
    // parent a node can have is n-1.
    // 2 ^ len <= n-1
    // len = O(log2n)
    static int getLen(int n) {
        int len = (int)(Math.log(n) / Math.log(2)) + 1;
        return len;
    }
 
    // jump represent 2D matrix to hold parent of node in jump matrix
    // here we pass reference of 2D matrix so that the change made
    // occur directly to the original matrix
    // len is same as defined above
    // n is total nodes in graph
    static void set_jump_pointer(int[][] jump, int[] node, int len, int n) {
        for (int j = 1; j <= len; j++)
            for (int i = 0; i < n; i++)
                jump[node[i]][j] = jump[jump[node[i]][j - 1]][j - 1];
    }
 
    // c -> it represent child
    // p -> it represent parent
    // i -> it represent node number
    // p=0 means the node is root node
    // here also we pass reference of 2D matrix
    // and depth vector so that the change made
    // occur directly to the original matrix and original vector
    static void constructGraph(int[][] jump, int[] node, int[] isNode, int c, int p, int i) {
        // enter the node in node array
        // it stores all the nodes in the graph
        node[i] = c;
 
        // to confirm that no child node have 2 parents
        if (isNode == 0) {
            isNode = 1;
            // make parent of x as y
            jump[0] = p;
        }
    }
 
    // function to jump to Lth parent of any node
    static void jumpPointer(int[][] jump, int[] isNode, int x, int L, int n) {
        int j = 0, curr = x, k = L;
 
        // to check if node is present in graph or not
        if (x > n || isNode[x] == 0) {
            System.out.println("Node is not present in graph");
            return;
        }
 
        // in this loop we decrease the value of L by L/2 and
        // increment j by 1 after each iteration, and check for set bit
        // if we get set bit then we update x with jth parent of x
        // as L becomes less than or equal to zero means
        // we have jumped to Lth parent of node x
        while (L > 0) {
            // to check if last bit is 1 or not
            if ((L & 1) == 1)
                x = jump[x][j];
 
            // use of shift operator to make
            // L = L/2 after every iteration
            L = L >> 1;
            j++;
        }
 
        System.out.println(k + "th parent of node " + curr + " is = " + x);
    }
 
    // Driver code
    public static void main(String[] args) {
        // n represent number of nodes
        int n= 11;
      // function to calculate len
// len -> it is the maximum length of
// array to hold parent of each node.
int len = (int) (Math.log(n) / Math.log(2)) + 1;
 
// initialization of parent matrix
int[][] jump = new int[n + 1][len + 1];
 
// node array is used to store all nodes
int[] node = new int[n + 1];
 
// isNode is an array to check whether
// a node is present in graph or not
int[] isNode = new int[n + 1];
 
// R stores root node
int R = 2;
 
// construction of graph
// here 0 represent that the node is root node
constructGraph(jump, node, isNode, 2, 0, 0);
constructGraph(jump, node, isNode, 5, 2, 1);
constructGraph(jump, node, isNode, 3, 5, 2);
constructGraph(jump, node, isNode, 4, 5, 3);
constructGraph(jump, node, isNode, 1, 5, 4);
constructGraph(jump, node, isNode, 7, 1, 5);
constructGraph(jump, node, isNode, 9, 1, 6);
constructGraph(jump, node, isNode, 10, 9, 7);
constructGraph(jump, node, isNode, 11, 10, 8);
constructGraph(jump, node, isNode, 6, 10, 9);
constructGraph(jump, node, isNode, 8, 10, 10);
 
// function to pre compute jump matrix
set_jump_pointer(jump, node, len, n);
 
// query to jump to parent using jump pointers
    // query to jump to 1st parent of node 2
    jumpPointer(jump, isNode, 2, 0, n);
 
    // query to jump to 2nd parent of node 4
    jumpPointer(jump, isNode, 4, 2, n);
 
    // query to jump to 3rd parent of node 8
    jumpPointer(jump, isNode, 8, 3, n);
 
    // query to jump to 5th parent of node 20
    jumpPointer(jump, isNode, 20, 5, n);
 
}}


Output

0th parent of node 2 is = 2
2th parent of node 4 is = 2
3th parent of node 8 is = 1
Node is not present in graph 

Complexity Analysis:

  • Time Complexity: O(logN) per query
  • Auxiliary Space: O(N * logN) 


Last Updated : 22 Feb, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads