Open In App

Proto Van Emde Boas Tree | Set 3 | Insertion and isMember Query

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

Please see previous articles on Proto Van Emde Boas Tree to understand these properly.
 

Procedure for Insert:  

  1. Base Case: If the size of Proto-VEB is 2 then assign true to the bit array( Here we in code we assign Proto-VEB(1) due to recursive structure and so now it is not nullptr and it act as true ) at the position of key.
  2. Until we reach at the base case, we will recursively call insert on cluster containing key and also now we use the key as the position of the key in that cluster instead of the query key.


Example: Let’s insert 2 into Proto-VEB (u=4): From the procedure of insert we will start recursion as size of Proto-VEB is greater than 2 so we recursively call insert() on cluster number 2/\sqrt{4}           which is 1 and it’s position 2%\sqrt{4}           which is 0 so recursive call will be insert(cluster[1], 0).
And cluster[1] is size 2 Proto-VEB, we reached at the base case so it will assign true at( in code Proto-VEB(1) as true ) cluster[1] 0th place.
Likewise, we will do the same procedure over summary.
See the image below for more clarity:
Follow the instructions written near the boxes from top to bottom.
 

Insertion-VEB


isMember procedure: This procedure returns boolean value according to whether the key is present in Proto-VEB or not. It is quite trivial to understand see the image above to get the idea about it. 

  1. Base Case: If the Proto-VEB size is 2 then check if bit array value at the key position is true or not and return value accordingly. (In code we check whether pointer at the key position is nullptr or not.)
  2. Recursion: we do recursive call over cluster containing key until we reach the base case.


Implementation of above algorithm:

CPP

// 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));
    }
}
 
// Driver code
int main()
{
    Proto_Van_Emde_Boas* hello = new Proto_Van_Emde_Boas(4);
 
    cout << isMember(hello, 3);
 
    insert(hello, 3);
 
    cout << isMember(hello, 3);
}

                    

Java

// Java implementation of the approach
import java.util.*;
 
class ProtoVanEmdeBoas {
  // Total number of keys
  int universeSize;
 
  // Summary
  ProtoVanEmdeBoas summary;
 
  // Clusters array of ProtoVanEmdeBoas pointers
  List<ProtoVanEmdeBoas> clusters;
 
  ProtoVanEmdeBoas(int size)
  {
    universeSize = size;
 
    // Base case
    if (size <= 2) {
      // Set summary to null as there is no more
      // summary for size 2
      summary = null;
      // List of two pointers, null in starting
      clusters
        = new ArrayList<ProtoVanEmdeBoas>(size);
      for (int i = 0; i < size; i++) {
        clusters.add(null);
      }
    }
    else {
      // Assign ProtoVanEmdeBoas(sqrt(u)) to summary
      summary = new ProtoVanEmdeBoas(root(size));
 
      // Creating array of ProtoVanEmdeBoas Tree
      // pointers of size sqrt(u) first all nulls are
      // going to assign
      clusters = new ArrayList<ProtoVanEmdeBoas>(
        root(size));
      for (int i = 0; i < root(size); i++) {
        clusters.add(null);
      }
 
      // Assign ProtoVanEmdeBoas(sqrt(u)) to all its
      // clusters
      for (int i = 0; i < root(size); i++) {
        clusters.set(
          i, new ProtoVanEmdeBoas(root(size)));
      }
    }
  }
 
  int root(int u) { return (int)Math.sqrt(u); }
 
  int high(int x) { return x / root(universeSize); }
 
  // Function to return position of x in cluster
  int low(int x) { return x % root(universeSize); }
 
  int generateIndex(int cluster, int position)
  {
    return cluster * root(universeSize) + position;
  }
}
 
// Driver code
class main
{
   
  // Function that returns true if the key is present in
  // the tree
  static boolean isMember(ProtoVanEmdeBoas helper,
                          int key)
  {
     
    // If key is greater than or equal to universeSize
    // then return false
    if (key >= helper.universeSize) {
      return false;
    }
 
    if (helper.universeSize == 2) {
      return helper.clusters.get(key) != null;
    }
    else {
      return isMember(
        helper.clusters.get(helper.high(key)),
        helper.low(key));
    }
  }
 
  // Function to insert a key in the tree
  static void insert(ProtoVanEmdeBoas helper, int key)
  {
    if (helper.universeSize == 2) {
      helper.clusters.set(key,
                          new ProtoVanEmdeBoas(1));
    }
    else {
      insert(helper.clusters.get(helper.high(key)),
             helper.low(key));
      // Also do the same recursion in summary VEB
      insert(helper.summary, helper.high(key));
    }
  }
 
  // Driver code
  public static void main(String[] args)
  {
    ProtoVanEmdeBoas hello = new ProtoVanEmdeBoas(4);
 
    // checking is member or not by calling isMember func.
    System.out.println(isMember(hello, 3));
 
    // inserting
    insert(hello, 3);
 
    // again checking is member or not by calling isMember func.
    System.out.println(isMember(hello, 3));
  }
}

                    

Python3

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(int(math.sqrt(size)))
            self.clusters = [Proto_Van_Emde_Boas(
                int(math.sqrt(size))) for _ in range(int(math.sqrt(size)))]
 
    def root(self, u):
        return int(math.sqrt(u))
 
    def high(self, x):
        return x // self.root(self.universe_size)
 
    def low(self, x):
        return x % self.root(self.universe_size)
 
    def generate_index(self, cluster, position):
        return cluster * self.root(self.universe_size) + position
 
 
def isMember(helper, key):
    if key >= helper.universe_size:
        return False
    elif helper.universe_size == 2:
        return helper.clusters[key] is not None
    else:
        return isMember(helper.clusters[helper.high(key)], helper.low(key))
 
 
def insert(helper, key):
    if helper.universe_size == 2:
        helper.clusters[key] = Proto_Van_Emde_Boas(1)
    else:
        insert(helper.clusters[helper.high(key)], helper.low(key))
        insert(helper.summary, helper.high(key))
 
 
# Driver code
hello = Proto_Van_Emde_Boas(4)
 
print(isMember(hello, 3))
 
insert(hello, 3)
 
print(isMember(hello, 3))

                    

Javascript

class Proto_Van_Emde_Boas {
    constructor(size) {
        this.universe_size = size;
        if (size <= 2) {
            this.summary = null;
            this.clusters = Array(size).fill(null);
        } else {
            this.summary = new Proto_Van_Emde_Boas(Math.floor(Math.sqrt(size)));
            this.clusters = Array(Math.floor(Math.sqrt(size))).fill(null).map(() => new Proto_Van_Emde_Boas(Math.floor(Math.sqrt(size))));
        }
    }
 
    root(u) {
        return Math.floor(Math.sqrt(u));
    }
 
    high(x) {
        return Math.floor(x / this.root(this.universe_size));
    }
 
    low(x) {
        return x % this.root(this.universe_size);
    }
 
    generate_index(cluster, position) {
        return cluster * this.root(this.universe_size) + position;
    }
}
 
function isMember(helper, key) {
    if (key >= helper.universe_size) return false;
    if (helper.universe_size === 2) {
        return helper.clusters[key] !== null;
    } else {
        return isMember(helper.clusters[helper.high(key)], helper.low(key));
    }
}
 
function insert(helper, 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));
    }
}
 
const hello = new Proto_Van_Emde_Boas(4);
 
console.log(isMember(hello, 3));
 
insert(hello, 3);
 
console.log(isMember(hello, 3));

                    

C#

using System;
using System.Collections.Generic;
 
public class ProtoVanEmdeBoas
{
    // Total number of keys
  public  int universeSize;
 
    // Summary
   public ProtoVanEmdeBoas summary;
 
    // Clusters array of ProtoVanEmdeBoas pointers
  public  List<ProtoVanEmdeBoas> clusters;
 
    public ProtoVanEmdeBoas(int size)
    {
        universeSize = size;
 
        // Base case
        if (size <= 2)
        {
            // Set summary to null as there is no more
            // summary for size 2
            summary = null;
            // List of two pointers, null in starting
            clusters = new List<ProtoVanEmdeBoas>(size);
            for (int i = 0; i < size; i++)
            {
                clusters.Add(null);
            }
        }
        else
        {
            // Assign ProtoVanEmdeBoas(sqrt(u)) to summary
            summary = new ProtoVanEmdeBoas(root(size));
 
            // Creating array of ProtoVanEmdeBoas Tree
            // pointers of size sqrt(u) first all nulls are
            // going to assign
            clusters = new List<ProtoVanEmdeBoas>(root(size));
            for (int i = 0; i < root(size); i++)
            {
                clusters.Add(null);
            }
 
            // Assign ProtoVanEmdeBoas(sqrt(u)) to all its
            // clusters
            for (int i = 0; i < root(size); i++)
            {
                clusters[i] = new ProtoVanEmdeBoas(root(size));
            }
        }
    }
 
  public  int root(int u) { return (int)Math.Sqrt(u); }
 
   public int high(int x) { return x / root(universeSize); }
 
    // Function to return position of x in cluster
 public int low(int x) { return x % root(universeSize); }
 
public int generateIndex(int cluster, int position)
    {
        return cluster * root(universeSize) + position;
    }
}
 
class Program
{
    // Function that returns true if the key is present in
    // the tree
    static bool isMember(ProtoVanEmdeBoas helper, int key)
    {
 
        // If key is greater than or equal to universeSize
        // then return false
        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 to insert a key in the tree
    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));
            // Also do the same recursion in summary VEB
            insert(helper.summary, helper.high(key));
        }
    }
 
    // Driver code
    static void Main()
    {
        ProtoVanEmdeBoas hello = new ProtoVanEmdeBoas(4);
 
        // checking is member or not by calling isMember func.
        Console.WriteLine(isMember(hello, 3));
 
        // inserting
        insert(hello, 3);
 
 
  Console.WriteLine(isMember(hello, 3));
}}

                    

Insert Algorithm Complexity Recurrence: 

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


This algorithm runs in O(log2(u)) worst-case time.
isMember Algorithm Complexity Recurrence:  

T(u) = T(\sqrt{u}) + O(1)


This algorithm runs in O(log2(log2(u))) worst-case time. 



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