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)).
1
6
summary
u
cluster
Keys
(Initialised only in
leaf nodes)
(Both initialised in non-
leaf nodes)
STRUCTURE OF THE NODE
typedef struct node
{
int u;
struct node *summary;
struct node **cluster;
int *keys;
}node;
node *createNode()
{
node *temp = (node *)malloc(sizeof(node));
temp->u = 0;
temp->summary = NULL;
temp->cluster = NULL;
return temp;
}
CreateNode:
• 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:
node *createTree(int u)
{
if(u == 2)
{
node *temp = createNode();
temp->u = u;
temp->summary = NULL;
temp->cluster = NULL;
temp->keys = (int *)malloc(8);
temp->keys[0] = 0;
temp->keys[1] = 0;
return temp;
}
int i;
node *temp = createNode();
temp->u = u;
temp->summary = createTree((int)sqrt(u));
temp->cluster = (node **)malloc(sizeof(node *) * (int)sqrt(u));
for(i = 0;i < (int)sqrt(u);i++){
temp->cluster[i] = createTree((int)sqrt(u));
}
return temp;
}
16
4
4
4
4
4
2
0 0
2
0 0
2
0 0
2
0 0
2
0 0
2
0 0
2
0 0
2
0 0
2
0 0
2
0 0
2
0 0
2
0 0
2
0 0
2
0 0
2
0 0
summary
u cluster
The Tree after calling
createTree()
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
• 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
void insert(node *head,int key)
{
if(head->u == 2)
{
head->keys[key] = 1;
return;
}
insert(head->cluster[high(key,head->u)],low(key,head->u));
insert(head->summary, high(key,head->u));
return;
}
Insert
16
4
4
4
4
4
2
1 1
2
1 1
2
0 1
2
0 1
2
0 0
2
1 1
2
1 1
2
1 1
2
0 1
2
0 0
2
0 0
2
0 0
2
0 1
2
0 0
2
1 1
summary
u cluster
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
The tree after inserting
2,3,4,5,7,14,15
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
• 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
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
4
4
4
4
4
2
1 1
2
1 1
2
0 1
2
0 1
2
0 0
2
1 1
2
1 1
2
1 1
2
0 1
2
0 0
2
0 0
2
0 0
2
0 1
2
0 0
2
0 1
summary
u cluster
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
The tree after deleting
14
• 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
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
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
16
4
4
4
4
4
2
1 1
2
1 1
2
0 1
2
0 1
2
0 0
2
1 1
2
1 1
2
1 1
2
0 1
2
0 0
2
0 0
2
0 0
2
0 1
2
0 0
2
0 1
summary
u cluster
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Minimum is 2 and
Maximum is 15
Orange arrow indicates the flow of
minimum function
• 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
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
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
THANK YOU
- Santhosh A

PVEB Tree.pptx

  • 2.
    SIGNIFICANCE • PVEB treeis 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)).
  • 3.
    1 6 summary u cluster Keys (Initialised only in leafnodes) (Both initialised in non- leaf nodes) STRUCTURE OF THE NODE
  • 4.
    typedef struct node { intu; struct node *summary; struct node **cluster; int *keys; }node; node *createNode() { node *temp = (node *)malloc(sizeof(node)); temp->u = 0; temp->summary = NULL; temp->cluster = NULL; return temp; } CreateNode:
  • 5.
    • Creates nodesand 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:
  • 6.
    node *createTree(int u) { if(u== 2) { node *temp = createNode(); temp->u = u; temp->summary = NULL; temp->cluster = NULL; temp->keys = (int *)malloc(8); temp->keys[0] = 0; temp->keys[1] = 0; return temp; } int i; node *temp = createNode(); temp->u = u; temp->summary = createTree((int)sqrt(u)); temp->cluster = (node **)malloc(sizeof(node *) * (int)sqrt(u)); for(i = 0;i < (int)sqrt(u);i++){ temp->cluster[i] = createTree((int)sqrt(u)); } return temp; }
  • 7.
    16 4 4 4 4 4 2 0 0 2 0 0 2 00 2 0 0 2 0 0 2 0 0 2 0 0 2 0 0 2 0 0 2 0 0 2 0 0 2 0 0 2 0 0 2 0 0 2 0 0 summary u cluster The Tree after calling createTree()
  • 8.
    int high(int x,intu) { 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 tothe 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
  • 10.
    void insert(node *head,intkey) { if(head->u == 2) { head->keys[key] = 1; return; } insert(head->cluster[high(key,head->u)],low(key,head->u)); insert(head->summary, high(key,head->u)); return; } Insert
  • 11.
    16 4 4 4 4 4 2 1 1 2 1 1 2 01 2 0 1 2 0 0 2 1 1 2 1 1 2 1 1 2 0 1 2 0 0 2 0 0 2 0 0 2 0 1 2 0 0 2 1 1 summary u cluster 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 The tree after inserting 2,3,4,5,7,14,15
  • 12.
    bool isMember(node *head,intkey) { 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 tothe 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,intkey){ 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
  • 15.
    16 4 4 4 4 4 2 1 1 2 1 1 2 01 2 0 1 2 0 0 2 1 1 2 1 1 2 1 1 2 0 1 2 0 0 2 0 0 2 0 0 2 0 1 2 0 0 2 0 1 summary u cluster 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 The tree after deleting 14
  • 16.
    • Traverse throughsummary 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
  • 19.
    16 4 4 4 4 4 2 1 1 2 1 1 2 01 2 0 1 2 0 0 2 1 1 2 1 1 2 1 1 2 0 1 2 0 0 2 0 0 2 0 0 2 0 1 2 0 0 2 0 1 summary u cluster 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Minimum is 2 and Maximum is 15 Orange arrow indicates the flow of minimum function
  • 20.
    • We traverseto 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,intkey){ 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,intkey){ 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
  • 23.