2. SIGNIFICANCE
• PVEB tree is used to reduce the time complexity of operations in a
dynamic array.
• The complexity of finding minimum, maximum, predecessor and
successor are significantly reduced in this tree.
• But the cost of insert, delete and member query is slightly greater than
normal arrays since normal arrays can do these operations in O(1).
• The Time Complexity of the tree is the height of the tree O(log(log(n)).
5. • Creates nodes and attaches with the tree.
• For leaf nodes, summary and cluster pointers are set to NULL and
keys array is initialised.
• For non-leaf nodes, summary and cluster pointers are allocated
space and keys array is not initialised
CreateTree:
8. int high(int x,int u)
{
return (int)floor(x/sqrt(u));
}
int low(int x,int u)
{
return x%(int)ceil(sqrt(u));
}
• high(x) is used to find the cluster number where the
element is present.
• low(x) is used to find the position at which the element
is present in the particular cluster returned by high(x).
• For ex, in a 16 element array, the clusters are {0,1,2,3},
{4,5,6,7}, {8,9,10,11}, {12,13,14,15}.
• Element 9 is present in cluster number 2 (9/root(16)),
the position of 9 in that cluster is 1 (9%root(16)).
High and Low
9. • Traverse to the bottom of the tree where u = 2 and set the particular bit to 1 and
recursively call summary pointer and modify it.
• We use high() and low() to find cluster number and offset of the number.
• We pass low(x) instead key in every call because the sub cluster (8,9,10,11) will be
considered as (0,1,2,3). So, the key value differs at every level.
Insert
12. bool isMember(node *head,int key)
{
if(head->u == 2)
{
if(head->keys[key] == 1)
return true;
return false;
}
return isMember(head->cluster[high(key,head->u)],low(key,head->u));
}
• Traverse to the leaf node and check if the bit is set and return.
IsMember
13. • Traverse to the leaf node and set the bit to 0.
• Check if any other value is set in the same cluster. If yes, no need to
update the summary value.
• If no, change the summary value to 0.
Delete
14. void del(node *head,int key){
if(head->u == 2){
head->keys[key] = 0;
return;
}
del(head->cluster[high(key,head->u)],low(key,head->u));
int isMemberAvailable = 0,i;
int hi = high(key,head->u);
int sq = (int)sqrt(head->u);
for(i = hi*sq; i < (hi+1)*sq; i++){
if(isMember(head,i))
{
isMemberAvailable = 1;
break;
}
}
if(isMemberAvailable == 0)
{
del(head->summary,high(key,head->u));
}}
Delete
16. • Traverse through summary nodes and check whether the first bit is set i.e. if any number is present in
the first half then check the second bit.
• If first bit is set, move to the cluster which is represented by that bit and repeat the same process until
you reach the leaf node and return the value.
• The expression index + (clust * (int)sqrt(head->u)) is used to calculate the actual value.
• The value 9 is represented as 1 in the leaf node, as 1 in a level above and as 9 in the head node.
• This can be calculated by cluster_no * sqrt(u) + offset. The cluster_no for 9 in the level below head is 0, u
is 4 and index is 1 => 1 + (0 * 2) = 1.
• In the head level, cluster_no = 2, u is 16 and index is the 1 (from the result of the level below). => 1 + (2
* 4) = 9.
Minimum
17. int minimum(node *head)
{
if(head->u == 2)
{
if(head->keys[0] == 1)
return 0;
else if (head->keys[1] == 1)
return 1;
return -1;
}
int clust = minimum(head->summary);
if(clust != -1)
{
int index = minimum(head->cluster[clust]);
return index + (clust * (int)sqrt(head->u));
}
}
Minimum
18. int maximum(node *head)
{
if(head->u == 2)
{
if(head->keys[1] == 1)
return 1;
else if (head->keys[0] == 1)
return 0;
return -1;
}
int clust = maximum(head->summary);
if(clust != -1)
{
int index = maximum(head->cluster[clust]);
return index + (clust * (int)sqrt(head->u));
}
}
The same logic as minimum but we check for
the second bit first and then first bit next which
do the traversal from the end.
Maximum
20. • We traverse to the leaf node and check whether our key is the second bit and there is a first bit set. If
yes, we need not do any calculation, we just return the value by calculating the value at each level
using the expression (high(key,head->u) * (int)sqrt(head->u)) + pred.
• If no immediate predecessor is found, we find the maximum of the left side clusters.
• Similarly, for successor we find if there are immediate successor else, we find the minimum of the
right-side clusters and return it.
Predecessor and Successor
21. int predecessor(node *head,int key){
if(head->u == 2){
if(key == 1 && head->keys[0] == 1)
return 0;
return -1;
}
int pred = predecessor(head->cluster[high(key,head->u)],low(key,head->u));
if (pred == -1){
int pred_clust = predecessor(head->summary,high(key,head->u));
if(pred_clust == -1)
{
return -1;
}
int max = maximum(head->cluster[pred_clust]);
return max + (pred_clust * (int)sqrt(head->u));
}
else
{
return (high(key,head->u) * (int)sqrt(head->u)) + pred;
}}
Predecessor
22. int successor(node *head,int key){
if(head->u == 2){
if(key == 0 && head->keys[1] == 1)
return 1;
return -1;
}
int sucsr = successor(head->cluster[high(key,head->u)],low(key,head->u));
if (sucsr == -1){
int pred_clust = successor(head->summary,high(key,head->u));
if(pred_clust == -1)
{
return -1;
}
int min = minimum(head->cluster[pred_clust]);
return min + (pred_clust * (int)sqrt(head->u));
}
else
{
return (high(key,head->u) * (int)sqrt(head->u)) + sucsr;
}}
Successor