Open In App

Proto Van Emde Boas Tree | Set 6 | Query : Successor and Predecessor

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

Please refer all previous articles on Proto Van Emde Boas Tree first.
Successor Query Procedure: 
 

  1. Base case: For Proto-VEB of size 2 the only possibility is that key is 0 and if the next key is present then it is its successor or there is no successor. So the same procedure is applied.
  2. Recursion: 
    • First, we will look in the present cluster (means the cluster in which the query key is present) if there is any key greater than query key is present then we will be the successor so we return it.
    • If above is not the case then we will recursively call successor procedure over summary to find next true value in summary. If there is no next true value in summary then we will return -1 as a sign that no larger key is present.
    • In the above operation if we find any next true value then we will find the minimum key present in that cluster which will be the successor of the query key.


See the image below for basic understanding of the operation of Successor query: 
 

Successor Query - Proto-VEB


Procedure for Predecessor is same as successor with some minor changes you should try to understand it from the above description for successor query. See the image below for basic understanding:
 

Predecessor Proto-VEB


Below is the implementation:
 

C++

// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
 
class Proto_Van_Emde_Boas {
public:
    // Total number of keys
    int universe_size;
 
    // Summary
    Proto_Van_Emde_Boas* summary;
 
    // Clusters array of Proto-VEB pointers
    vector<Proto_Van_Emde_Boas*> clusters;
 
    int root(int u)
    {
        return (int)sqrt(u);
    }
 
    // Function to return cluster numbers
    // in which key is present
    int high(int x)
    {
        return x / root(universe_size);
    }
 
    // Function to return position of x in cluster
    int low(int x)
    {
        return x % root(universe_size);
    }
 
    // Function to return the index from
    // cluster number and position
    int generate_index(int cluster, int position)
    {
        return cluster * root(universe_size) + position;
    }
 
    // Constructor
    Proto_Van_Emde_Boas(int size)
    {
        universe_size = size;
 
        // Base case
        if (size <= 2) {
 
            // Set summary to nullptr as there is no
            // more summary for size 2
            summary = nullptr;
 
            // Vector of two pointers
            // nullptr in starting
            clusters = vector<Proto_Van_Emde_Boas*>(size, nullptr);
        }
        else {
 
            // Assigning Proto-VEB(sqrt(u)) to summary
            summary = new Proto_Van_Emde_Boas(root(size));
 
            // Creating array of Proto-VEB Tree pointers of size sqrt(u)
            // first all nullptrs are going to assign
            clusters = vector<Proto_Van_Emde_Boas*>(root(size), nullptr);
 
            // Assigning Proto-VEB(sqrt(u)) to all its clusters
            for (int i = 0; i < root(size); i++) {
                clusters[i] = new Proto_Van_Emde_Boas(root(size));
            }
        }
    }
};
 
// Function that returns true if the
// key is present in the tree
bool isMember(Proto_Van_Emde_Boas* helper, int key)
{
 
    // If key is greater then universe_size then
    // returns false
    if (key >= helper->universe_size)
        return false;
 
    // If we reach at base case
    // the just return whether
    // pointer is nullptr then false
    // else return true
    if (helper->universe_size == 2) {
        return helper->clusters[key];
    }
    else {
 
        // Recursively go deep into the
        // level of Proto-VEB tree using its
        // cluster index and its position
        return isMember(helper->clusters[helper->high(key)],
                        helper->low(key));
    }
}
 
// Function to insert a key in the tree
void insert(Proto_Van_Emde_Boas*& helper, int key)
{
    // If we reach at base case
    // then assign Proto-VEB(1) in place
    // of nullptr
    if (helper->universe_size == 2) {
        helper->clusters[key] = new Proto_Van_Emde_Boas(1);
    }
    else {
 
        // Recursively using index of cluster and its
        // position in cluster
        insert(helper->clusters[helper->high(key)],
               helper->low(key));
 
        // Also do the same recursion in summary VEB
        insert(helper->summary, helper->high(key));
    }
}
 
// Function to return the minimum key from the tree
int minimum(Proto_Van_Emde_Boas* helper)
{
    // Base case chooses the least key
    // present in the cluster
    if (helper->universe_size == 2) {
        if (helper->clusters[0]) {
            return 0;
        }
        else if (helper->clusters[1]) {
            return 1;
        }
 
        // No keys present then return -1
        return -1;
    }
    else {
 
        // Recursively find in summary for
        // first 1 present in Proto-VEB
        int minimum_cluster = minimum(helper->summary);
        int offset;
 
        // If no key is present in
        // the cluster then return -1
        if (minimum_cluster == -1) {
            return -1;
        }
        else {
 
            // Recursively find the position of the key
            // in the minimum_cluster
            offset = minimum(helper->clusters[minimum_cluster]);
 
            // Returns overall index of minimum key
            return helper->generate_index(minimum_cluster, offset);
        }
    }
}
 
// Function to return the maximum key from the tree
int maximum(Proto_Van_Emde_Boas* helper)
{
 
    // Return the maximum key present in
    // the cluster
    if (helper->universe_size == 2) {
        if (helper->clusters[1]) {
            return 1;
        }
        else if (helper->clusters[0]) {
            return 0;
        }
 
        // Return -1 if no keys present in the
        // cluster
        return -1;
    }
    else {
 
        // Recursively find the last 1 present
        // in the summary
        int maximum_cluster = maximum(helper->summary);
        int offset;
 
        // If no key is present in
        // the cluster then return -1
        if (maximum_cluster == -1) {
            return -1;
        }
        else {
 
            // Recursively find the position of the key
            // in the maximum_cluster
            offset = maximum(helper->clusters[maximum_cluster]);
            return helper->generate_index(maximum_cluster, offset);
        }
    }
}
 
// Function to return the successor of key in the tree
int successor(Proto_Van_Emde_Boas* helper, int key)
{
    // Base case, returns key greater than
    // our query key in the cluster if present
    // else returns -1
    if (helper->universe_size == 2) {
        if (key == 0 && helper->clusters[1])
            return 1;
        else
            return -1;
    }
    else {
 
        // Check if any key is greater than query key in the cluster
        int offset = successor(helper->clusters[helper->high(key)],
                               helper->low(key));
 
        // If it is present then return its index
        if (offset != -1)
            return helper->generate_index(helper->high(key), offset);
        else {
 
            // If no successor is present within the cluster then
            // go to the summary and find the next summary with
            // key present(1) named successor_cluster
            int successor_cluster = successor(helper->summary,
                                              helper->high(key));
 
            // If no next 1 in the summary then return -1
            if (successor_cluster == -1)
                return -1;
            else {
 
                // Find the minimum key in the successor_cluster
                offset = minimum(helper->clusters[successor_cluster]);
 
                // Generate its index and return
                return helper->generate_index(successor_cluster, offset);
            }
        }
    }
}
 
// Function to return the predecessor of key in the tree
int predecessor(Proto_Van_Emde_Boas* helper, int key)
{
 
    // Base case, find smaller key present in
    // the cluster
    // If present else return -1
    if (helper->universe_size == 2) {
        if (key == 1 && helper->clusters[0])
            return 0;
        else
            return -1;
    }
    else {
 
        // Check if any key is lower than query key in the cluster
        int offset = predecessor(helper->clusters[helper->high(key)],
                                 helper->low(key));
 
        // If it is present then return its index
        if (offset != -1)
            return helper->generate_index(helper->high(key), offset);
        else {
 
            // If no predecessor is present within the cluster then
            // go to the summary and find the next summary with
            // key present(1) named predecessor_cluster
            int predecessor_cluster = predecessor(helper->summary,
                                                  helper->high(key));
 
            // If no next 1 in the summary then return -1
            if (predecessor_cluster == -1)
                return -1;
            else {
 
                // Find the maximum key in the predecessor_cluster
                offset = maximum(helper->clusters[predecessor_cluster]);
 
                // Generate its index and return
                return helper->generate_index(predecessor_cluster, offset);
            }
        }
    }
}
 
// Function to delete a key from the tree
void pveb_delete(Proto_Van_Emde_Boas*& helper, int key)
{
 
    // Base case: If the key is present
    // then make it nullptr
    if (helper->universe_size == 2) {
        if (helper->clusters[key]) {
            delete helper->clusters[key];
            helper->clusters[key] = nullptr;
        }
    }
    else {
 
        // Recursive delete to reach at the base case
        pveb_delete(helper->clusters[helper->high(key)], helper->low(key));
 
        bool isanyinCluster = false;
 
        // Iterate over the cluster of keys to check whether
        // any other key is present within that cluster
        // If yes then we should not update summary to 0
        // else update summary to 0
        for (int i = helper->high(key) * helper->root(helper->universe_size);
             i < (helper->high(key) + 1) * helper->root(helper->universe_size);
             i++) {
 
            // If member is present then break the loop
            if (isMember(helper->clusters[helper->high(key)], i)) {
                isanyinCluster = true;
                break;
            }
        }
 
        // If no member is present then
        // update summary to zero
        if (isanyinCluster == false) {
            pveb_delete(helper->summary, helper->high(key));
        }
    }
}
 
// Driver code
int main()
{
    Proto_Van_Emde_Boas* hello = new Proto_Van_Emde_Boas(16);
 
    cout << boolalpha;
 
    insert(hello, 2);
 
    insert(hello, 13);
 
    insert(hello, 3);
 
    cout << successor(hello, 3) << endl;
 
    cout << predecessor(hello, 13) << endl;
}

                    

Java

#include <bits/stdc++.h>
using namespace std;
class Proto_Van_Emde_Boas {
public:
    int universe_size;
    Proto_Van_Emde_Boas* summary;
    vector<Proto_Van_Emde_Boas*> clusters;
    int root(int u)
    {
        return (int)sqrt(u);
    }
    int high(int x)
    {
        return x / root(universe_size);
    }
    int low(int x)
    {
        return x % root(universe_size);
    }
    int generate_index(int cluster, int position)
    {
        return cluster * root(universe_size) + position;
    }
    Proto_Van_Emde_Boas(int size)
    {
        universe_size = size;
        if (size <= 2) {
            summary = nullptr;
            clusters = vector<Proto_Van_Emde_Boas*>(size, nullptr);
        }
        else{
            summary = new Proto_Van_Emde_Boas(root(size));
            clusters = vector<Proto_Van_Emde_Boas*>(root(size), nullptr);
            for (int i = 0; i < root(size); i++) {
                clusters[i] = new Proto_Van_Emde_Boas(root(size));
            }
        }
    }
};
bool isMember(Proto_Van_Emde_Boas* helper, int key)
{
    if (key >= helper->universe_size)
        return false;
    if (helper->universe_size == 2) {
        return helper->clusters[key];
    }
    else {
        return isMember(helper->clusters[helper->high(key)],
                        helper->low(key));
    }
}
void insert(Proto_Van_Emde_Boas*& helper, int key)
{
    if (helper->universe_size == 2) {
        helper->clusters[key] = new Proto_Van_Emde_Boas(1);
    }
    else {
        insert(helper->clusters[helper->high(key)],
               helper->low(key));
        insert(helper->summary, helper->high(key));
    }
}
int minimum(Proto_Van_Emde_Boas* helper)
{
    if (helper->universe_size == 2) {
        if (helper->clusters[0]) {
            return 0;
        }
        else if (helper->clusters[1]) {
            return 1;
        }
        return -1;
    }
    else {
        int minimum_cluster = minimum(helper->summary);
        int offset;
        if (minimum_cluster == -1) {
            return -1;
        }
        else {
            offset = minimum(helper->clusters[minimum_cluster]);
            return helper->generate_index(minimum_cluster, offset);
        }
    }
}
int maximum(Proto_Van_Emde_Boas* helper)
{
    if (helper->universe_size == 2) {
        if (helper->clusters[1]) {
            return 1;
        }
        else if (helper->clusters[0]) {
            return 0;
        }
        return -1;
    }
    else {
        int maximum_cluster = maximum(helper->summary);
        int offset;
        if (maximum_cluster == -1) {
            return -1;
        }
        else {
            offset = maximum(helper->clusters[maximum_cluster]);
            return helper->generate_index(maximum_cluster, offset);
        }
    }
}
int successor(Proto_Van_Emde_Boas* helper, int key)
{
    if (helper->universe_size == 2) {
        if (key == 0 && helper->clusters[1])
            return 1;
        else
            return -1;
    }
    else {
        int offset = successor(helper->clusters[helper->high(key)],
                               helper->low(key));
        if (offset != -1)
            return helper->generate_index(helper->high(key), offset);
        else {
            int successor_cluster = successor(helper->summary,
                                              helper->high(key));
            if (successor_cluster == -1)
                return -1;
            else {
                offset = minimum(helper->clusters[successor_cluster]);
                return helper->generate_index(successor_cluster, offset);
            }
        }
    }
}
int predecessor(Proto_Van_Emde_Boas* helper, int key)
{
    if (helper->universe_size == 2) {
        if (key == 1 && helper->clusters[0])
            return 0;
        else
            return -1;
    }
    else {
        int offset = predecessor(helper->clusters[helper->high(key)],
                                 helper->low(key));
        if (offset != -1)
            return helper->generate_index(helper->high(key), offset);
        else {
            int predecessor_cluster = predecessor(helper->summary,
                                                  helper->high(key));
            if (predecessor_cluster == -1)
                return -1;
            else {
                offset = maximum(helper->clusters[predecessor_cluster]);
                return helper->generate_index(predecessor_cluster, offset);
            }
        }
    }
}
void pveb_delete(Proto_Van_Emde_Boas*& helper, int key)
{
    if (helper->universe_size == 2) {
        if (helper->clusters[key]) {
            delete helper->clusters[key];
            helper->clusters[key] = nullptr;
        }
    }
    else {
        pveb_delete(helper->clusters[helper->high(key)], helper->low(key));
        bool isanyinCluster = false;
        for (int i = helper->high(key) * helper->root(helper->universe_size);
             i < (helper->high(key) + 1) * helper->root(helper->universe_size);
             i++) {
            if (isMember(helper->clusters[helper->high(key)], i)) {
                isanyinCluster = true;
                break;
            }
        }
        if (isanyinCluster == false) {
            pveb_delete(helper->summary, helper->high(key));
        }
    }
}
int main()
{
    Proto_Van_Emde_Boas* hello = new Proto_Van_Emde_Boas(16);
    cout << boolalpha;
    insert(hello, 2);
    insert(hello, 13);
    insert(hello, 3);
    cout << successor(hello, 3) << endl;
    cout << predecessor(hello, 13) << endl;
}

                    

Python3

# Python3 implementation of the approach
import math
 
class Proto_Van_Emde_Boas:
    def __init__(self, size):
       
        self.universe_size = size
        if size <= 2:
            self.summary = None
            self.clusters = [None] * size
        else:
            self.summary = Proto_Van_Emde_Boas(self._root(size))
            self.clusters = [Proto_Van_Emde_Boas(self._root(size)) for _ in range(self._root(size))]
 
    def _root(self, u):
        return int(math.sqrt(u))
 
    # Function to return cluster numbers
    # in which key is present
    def high(self, x):
        return x // self._root(self.universe_size)
 
    # Function to return position of x in cluster
    def low(self, x):
        return x % self._root(self.universe_size)
 
    # Function to return the index from
    # cluster number and position
    def generate_index(self, cluster, position):
        return cluster * self._root(self.universe_size) + position
 
# Function that returns true if the
# key is present in the tree
def isMember(helper, key):
   
    # If key is greater then universe_size then
    # returns false
    if key >= helper.universe_size:
        return False
       
    # If we reach at base case
    # the just return whether
    # pointer is nullptr then false
    # else return true
    if helper.universe_size == 2:
        return helper.clusters[key]
    else:
       
        # Recursively go deep into the
        # level of Proto-VEB tree using its
        # cluster index and its position
        return isMember(helper.clusters[helper.high(key)], helper.low(key))
 
# Function to insert a key in the tree
def insert(helper, key):
   
    # If we reach at base case
    # then assign Proto-VEB(1) in place
    # of nullptr
    if helper.universe_size == 2:
        helper.clusters[key] = Proto_Van_Emde_Boas(1)
    else:
       
        # Recursively using index of cluster and its
        # position in cluster
        insert(helper.clusters[helper.high(key)], helper.low(key))
         
        # Also do the same recursion in summary VEB
        insert(helper.summary, helper.high(key))
 
# Function to return the minimum key from the tree
def minimum(helper):
   
    # Base case chooses the least key
    # present in the cluster
    if helper.universe_size == 2:
        if helper.clusters[0]:
            return 0
        elif helper.clusters[1]:
            return 1
           
        # No keys present then return -1
        return -1
    else:
       
        # Recursively find in summary for
        # first 1 present in Proto-VEB
        minimum_cluster = minimum(helper.summary)
         
        # If no key is present in
        # the cluster then return -1
        if minimum_cluster == -1:
            return -1
        else:
           
            # Recursively find the position of the key
            # in the minimum_cluster
            offset = minimum(helper.clusters[minimum_cluster])
             
            # Returns overall index of minimum key
            return helper.generate_index(minimum_cluster, offset)
 
# Function to return the maximum key from the tree
def maximum(helper):
   
    # Return the maximum key present in
    # the cluster
    if helper.universe_size == 2:
        if helper.clusters[1]:
            return 1
        elif helper.clusters[0]:
            return 0
           
        # Return -1 if no keys present in the
        # cluster
        return -1
    else:
       
        # Recursively find the last 1 present
        # in the summary
        maximum_cluster = maximum(helper.summary)
         
        # If no key is present in
        # the cluster then return -1
        if maximum_cluster == -1:
            return -1
        else:
           
            # Recursively find the position of the key
            # in the maximum_cluster
            offset = maximum(helper.clusters[maximum_cluster])
            return helper.generate_index(maximum_cluster, offset)
 
# Function to return the successor of key in the tree
def successor(helper, key):
   
    # Base case, returns key greater than
    # our query key in the cluster if present
    # else returns -1
    if helper.universe_size == 2:
        if key == 0 and helper.clusters[1]:
            return 1
        else:
            return -1
    else:
       
        # Check if any key is greater than query key in the cluster
        offset = successor(helper.clusters[helper.high(key)], helper.low(key))
         
        # If it is present then return its index
        if offset != -1:
            return helper.generate_index(helper.high(key), offset)
        else:
           
            # If no successor is present within the cluster then
            # go to the summary and find the next summary with
            # key present(1) named successor_cluster
            successor_cluster = successor(helper.summary, helper.high(key))
             
            # If no next 1 in the summary then return -1
            if successor_cluster == -1:
                return -1
            else:
               
                # Find the minimum key in the successor_cluster
                offset = minimum(helper.clusters[successor_cluster])
                 
                # Generate its index and return
                return helper.generate_index(successor_cluster, offset)
               
# Function to return the predecessor of key in the tree
def predecessor(helper, key):
   
    # Base case, find smaller key present in
    # the cluster
    # If present else return -1
    if helper.universe_size == 2:
        if key == 1 and helper.clusters[0]:
            return 0
        else:
            return -1
    else:
       
        # Check if any key is lower than query key in the cluster
        offset = predecessor(helper.clusters[helper.high(key)], helper.low(key))
         
        # If it is present then return its index
        if offset != -1:
            return helper.generate_index(helper.high(key), offset)
        else:
           
            # If no predecessor is present within the cluster then
            # go to the summary and find the next summary with
            # key present(1) named predecessor_cluster
            predecessor_cluster = predecessor(helper.summary, helper.high(key))
             
            # If no next 1 in the summary then return -1
            if predecessor_cluster == -1:
                return -1
            else:
               
                # Find the maximum key in the predecessor_cluster
                offset = maximum(helper.clusters[predecessor_cluster])
                 
                # Generate its index and return
                return helper.generate_index(predecessor_cluster, offset)
     
# Function to delete a key from the tree
def pveb_delete(helper, key):
   
    # Base case: If the key is present
    # then make it nullptr
    if helper.universe_size == 2:
        if helper.clusters[key]:
            del helper.clusters[key]
            helper.clusters[key] = None
    else:
       
        # Recursive delete to reach at the base case
        pveb_delete(helper.clusters[helper.high(key)], helper.low(key))
        is_any_in_cluster = False
         
        # Iterate over the cluster of keys to check whether
        # any other key is present within that cluster
        # If yes then we should not update summary to 0
        # else update summary to 0
        for i in range(helper.high(key) * helper.root(helper.universe_size),
                       (helper.high(key) + 1) * helper.root(helper.universe_size)):
             
            # If member is present then break the loop
            if isMember(helper.clusters[helper.high(key)], i):
                is_any_in_cluster = True
                break
                 
        # If no member is present then
        # update summary to zero
        if not is_any_in_cluster:
            pveb_delete(helper.summary, helper.high(key))
 
# Driver code
hello = Proto_Van_Emde_Boas(16)
 
insert(hello, 2)
 
insert(hello, 13)
 
insert(hello, 3)
 
print(successor(hello, 3))
 
print(predecessor(hello, 13))
 
# This code is contributed by Prajwal Kandekar

                    

C#

// C# Code
 
using System;
 
public class ProtoVanEmdeBoas
{
    public int UniverseSize { get; private set; }
    public ProtoVanEmdeBoas Summary { get; private set; }
    public ProtoVanEmdeBoas[] Clusters { get; private set; }
 
    public ProtoVanEmdeBoas(int size)
    {
        UniverseSize = size;
 
        if (size <= 2)
        {
            Summary = null;
            Clusters = new ProtoVanEmdeBoas[size];
        }
        else
        {
            Summary = new ProtoVanEmdeBoas(Root(size));
            Clusters = new ProtoVanEmdeBoas[Root(size)];
 
            for (int i = 0; i < Root(size); i++)
            {
                Clusters[i] = new ProtoVanEmdeBoas(Root(size));
            }
        }
    }
 
    public int High(int x)
    {
        return x / Root(UniverseSize);
    }
 
    public int Low(int x)
    {
        return x % Root(UniverseSize);
    }
 
    public int GenerateIndex(int cluster, int position)
    {
        return cluster * Root(UniverseSize) + position;
    }
 
    public int Root(int u)
    {
        return (int)Math.Sqrt(u);
    }
}
 
public class Program
{
    static bool IsMember(ProtoVanEmdeBoas helper, int key)
    {
        if (key >= helper.UniverseSize)
        {
            return false;
        }
 
        if (helper.UniverseSize == 2)
        {
            return helper.Clusters[key] != null;
        }
        else
        {
            return IsMember(helper.Clusters[helper.High(key)], helper.Low(key));
        }
    }
 
    static void Insert(ProtoVanEmdeBoas helper, int key)
    {
        if (helper.UniverseSize == 2)
        {
            helper.Clusters[key] = new ProtoVanEmdeBoas(1);
        }
        else
        {
            Insert(helper.Clusters[helper.High(key)], helper.Low(key));
            Insert(helper.Summary, helper.High(key));
        }
    }
 
    static int Minimum(ProtoVanEmdeBoas helper)
    {
        if (helper.UniverseSize == 2)
        {
            if (helper.Clusters[0] != null)
            {
                return 0;
            }
            else if (helper.Clusters[1] != null)
            {
                return 1;
            }
 
            return -1;
        }
        else
        {
            int minimumCluster = Minimum(helper.Summary);
 
            if (minimumCluster == -1)
            {
                return -1;
            }
            else
            {
                int offset = Minimum(helper.Clusters[minimumCluster]);
                return helper.GenerateIndex(minimumCluster, offset);
            }
        }
    }
 
    static int Maximum(ProtoVanEmdeBoas helper)
    {
        if (helper.UniverseSize == 2)
        {
            if (helper.Clusters[1] != null)
            {
                return 1;
            }
            else if (helper.Clusters[0] != null)
            {
                return 0;
            }
 
            return -1;
        }
        else
        {
            int maximumCluster = Maximum(helper.Summary);
 
            if (maximumCluster == -1)
            {
                return -1;
            }
            else
            {
                int offset = Maximum(helper.Clusters[maximumCluster]);
                return helper.GenerateIndex(maximumCluster, offset);
            }
        }
    }
 
    static int Successor(ProtoVanEmdeBoas helper, int key)
    {
        if (helper.UniverseSize == 2)
        {
            if (key == 0 && helper.Clusters[1] != null)
            {
                return 1;
            }
            else
            {
                return -1;
            }
        }
        else
        {
            int offset = Successor(helper.Clusters[helper.High(key)], helper.Low(key));
 
            if (offset != -1)
            {
                return helper.GenerateIndex(helper.High(key), offset);
            }
            else
            {
                int successorCluster = Successor(helper.Summary, helper.High(key));
 
                if (successorCluster == -1)
                {
                    return -1;
                }
                else
                {
                    int offsetInCluster = Minimum(helper.Clusters[successorCluster]);
                    return helper.GenerateIndex(successorCluster, offsetInCluster);
                }
            }
        }
    }
 
    static int Predecessor(ProtoVanEmdeBoas helper, int key)
    {
        if (helper.UniverseSize == 2)
        {
            if (key == 1 && helper.Clusters[0] != null)
            {
                return 0;
            }
            else
            {
                return -1;
            }
        }
        else
        {
            int offset = Predecessor(helper.Clusters[helper.High(key)], helper.Low(key));
 
            if (offset != -1)
            {
                return helper.GenerateIndex(helper.High(key), offset);
            }
            else
            {
                int predecessorCluster = Predecessor(helper.Summary, helper.High(key));
 
                if (predecessorCluster == -1)
                {
                    return -1;
                }
                else
                {
                    int offsetInCluster = Maximum(helper.Clusters[predecessorCluster]);
                    return helper.GenerateIndex(predecessorCluster, offsetInCluster);
                }
            }
        }
    }
 
    static void PvebDelete(ProtoVanEmdeBoas helper, int key)
    {
        if (helper.UniverseSize == 2)
        {
            if (helper.Clusters[key] != null)
            {
                helper.Clusters[key] = null;
            }
        }
        else
        {
            PvebDelete(helper.Clusters[helper.High(key)], helper.Low(key));
 
            bool isAnyInCluster = false;
 
            for (int i = helper.High(key) * helper.Root(helper.UniverseSize);
                i < (helper.High(key) + 1) * helper.Root(helper.UniverseSize);
                i++)
            {
                if (IsMember(helper.Clusters[helper.High(key)], i))
                {
                    isAnyInCluster = true;
                    break;
                }
            }
 
            if (!isAnyInCluster)
            {
                PvebDelete(helper.Summary, helper.High(key));
            }
        }
    }
 
    static void Main()
    {
        ProtoVanEmdeBoas hello = new ProtoVanEmdeBoas(16);
 
        Insert(hello, 2);
        Insert(hello, 13);
        Insert(hello, 3);
 
        Console.WriteLine(Successor(hello, 3));
        Console.WriteLine(Predecessor(hello, 13));
    }
}
 
// This code is contributed by guptapratik

                    

Javascript

// Javascript code
 
class ProtoVanEmdeBoas {
    constructor(size) {
        this.universeSize = size;
 
        if (size <= 2) {
            this.summary = null;
            this.clusters = new Array(size).fill(null);
        } else {
            this.summary = new ProtoVanEmdeBoas(this.root(size));
            this.clusters = new Array(this.root(size)).fill(null).map(() => new ProtoVanEmdeBoas(this.root(size)));
        }
    }
 
    root(u) {
        return Math.floor(Math.sqrt(u));
    }
 
    high(x) {
        return Math.floor(x / this.root(this.universeSize));
    }
 
    low(x) {
        return x % this.root(this.universeSize);
    }
 
    generateIndex(cluster, position) {
        return cluster * this.root(this.universeSize) + position;
    }
}
 
function isMember(helper, key) {
    if (key >= helper.universeSize) {
        return false;
    }
 
    if (helper.universeSize === 2) {
        return helper.clusters[key] !== null;
    } else {
        return isMember(helper.clusters[helper.high(key)], helper.low(key));
    }
}
 
function insert(helper, key) {
    if (helper.universeSize === 2) {
        helper.clusters[key] = new ProtoVanEmdeBoas(1);
    } else {
        insert(helper.clusters[helper.high(key)], helper.low(key));
        insert(helper.summary, helper.high(key));
    }
}
 
function minimum(helper) {
    if (helper.universeSize === 2) {
        if (helper.clusters[0] !== null) {
            return 0;
        } else if (helper.clusters[1] !== null) {
            return 1;
        }
        return -1;
    } else {
        const minimumCluster = minimum(helper.summary);
 
        if (minimumCluster === -1) {
            return -1;
        } else {
            const offset = minimum(helper.clusters[minimumCluster]);
            return helper.generateIndex(minimumCluster, offset);
        }
    }
}
 
function maximum(helper) {
    if (helper.universeSize === 2) {
        if (helper.clusters[1] !== null) {
            return 1;
        } else if (helper.clusters[0] !== null) {
            return 0;
        }
        return -1;
    } else {
        const maximumCluster = maximum(helper.summary);
 
        if (maximumCluster === -1) {
            return -1;
        } else {
            const offset = maximum(helper.clusters[maximumCluster]);
            return helper.generateIndex(maximumCluster, offset);
        }
    }
}
 
function successor(helper, key) {
    if (helper.universeSize === 2) {
        if (key === 0 && helper.clusters[1] !== null) {
            return 1;
        } else {
            return -1;
        }
    } else {
        const offset = successor(helper.clusters[helper.high(key)], helper.low(key));
 
        if (offset !== -1) {
            return helper.generateIndex(helper.high(key), offset);
        } else {
            const successorCluster = successor(helper.summary, helper.high(key));
 
            if (successorCluster === -1) {
                return -1;
            } else {
                const offsetInCluster = minimum(helper.clusters[successorCluster]);
                return helper.generateIndex(successorCluster, offsetInCluster);
            }
        }
    }
}
 
function predecessor(helper, key) {
    if (helper.universeSize === 2) {
        if (key === 1 && helper.clusters[0] !== null) {
            return 0;
        } else {
            return -1;
        }
    } else {
        const offset = predecessor(helper.clusters[helper.high(key)], helper.low(key));
 
        if (offset !== -1) {
            return helper.generateIndex(helper.high(key), offset);
        } else {
            const predecessorCluster = predecessor(helper.summary, helper.high(key));
 
            if (predecessorCluster === -1) {
                return -1;
            } else {
                const offsetInCluster = maximum(helper.clusters[predecessorCluster]);
                return helper.generateIndex(predecessorCluster, offsetInCluster);
            }
        }
    }
}
 
function pvebDelete(helper, key) {
    if (helper.universeSize === 2) {
        if (helper.clusters[key] !== null) {
            helper.clusters[key] = null;
        }
    } else {
        pvebDelete(helper.clusters[helper.high(key)], helper.low(key));
 
        let isAnyInCluster = false;
 
        for (let i = helper.high(key) * helper.root(helper.universeSize);
            i < (helper.high(key) + 1) * helper.root(helper.universeSize);
            i++) {
            if (isMember(helper.clusters[helper.high(key)], i)) {
                isAnyInCluster = true;
                break;
            }
        }
 
        if (!isAnyInCluster) {
            pvebDelete(helper.summary, helper.high(key));
        }
    }
}
 
const hello = new ProtoVanEmdeBoas(16);
insert(hello, 2);
insert(hello, 13);
insert(hello, 3);
 
console.log(successor(hello, 3));
console.log(predecessor(hello, 13));
 
// This code is contributed by guptapratik

                    

Recurrence Relation for Successor and Predecessor Queries:
 

T(u) = T(u) = 2T(\sqrt{u})) + O(log2(\sqrt{u}))

Time Complexity: O(log2(u)*log2(log2(u))) per query
Auxiliary Space: O(N). 



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