介绍
van Emde Boas tree是一种适用于0-u数据存储的一种数据类型。它每次根据u的一半来依次递减,直到最后减少到2为止。对数据有一定要求:要求u是2的2k或者2k+1次方。
单个结点的结构如下:
每个结点包含以下数据:其中u是当前结点的cluster的数量;min和当前结点中最小结点的数,而且最小值不出来在cluster当中; max是当前结点中最大结点的数;其中min和max在根结点和在子结点中的定义不一样,在根结点中,直接就是数据的值,而在子结点中,则是结点在当前结点中的cluster的序号;summary是一个指向子summary结点的指针,cluster是指向当前子cluster结点的指针。
下面看一个例子:
以上是一个数据集合{2,3,4,5,7,14,15}的van Emde Boas Tree图。可以看到,在最基结点,就是u==2的结点是,summary和cluster是没有的,只保存有min和max的值。
实现
下面来看下代码是如何实现它的,首先,根据上面结点的结构,我们来定义树的结构:
typedef struct Node_ { int u; int min; int max; struct Node_ *summary; struct Node_ **cluster; }Node; typedef struct VanEmdeBoasTree_ { Node *root; }VanEmdeBoasTree; static VanEmdeBoasTree * g_VEB = nullptr;
然后,再来初始化这颗树,我们要定义一个数据的开始长度,而所有的数据大小不能超过这个值。
void createCluster(Node *cluster, int u) { cluster->u = u; cluster->min = NIL; cluster->max = NIL; if (2 == u) { cluster->cluster = nullptr; cluster->summary = nullptr; }else { int sqrt_u = (int)sqrt(u * 1.0); cluster->summary = new struct Node_; createCluster(cluster->summary, sqrt_u); cluster->cluster = new struct Node_ *[sqrt_u]; for (int i = 0; i < sqrt_u; ++ i) { cluster->cluster[i] = new struct Node_; createCluster(cluster->cluster[i], sqrt_u); } } } void init(int u) { g_VEB = new VanEmdeBoasTree; g_VEB->root = new Node; createCluster(g_VEB->root, u); }
刚开始里面是没有任何数据的。接着我们先对其做一些简单的基本操作,比如求最小值和最大值:
int min(Node *node) { return node->min; } int max(Node *node) { return node->max; }
这个最简单了,因为根结点里面就已经自带了。
接着在讲查询之前,我们先要进行定义几个公式:就是根据给定的一个数,求出它所在的cluster以及它所在的cluster内的序号。
int high(int x, int u) { return (int)floor(x / sqrt(u * 1.0)); } int low(int x, int u) { return x % (int)sqrt(u * 1.0); }
high函数可以求出给定的值所在的cluster,low可以求出给定的值所在的cluster内的序号。接着便是根据x的high值和low值可以求出x的值是多少:
int index(int x, int y, int u) { return x * (int)sqrt(u * 1.0) + y; }
以上3个公式中u的值皆是当前结点的u值。
那么查询就简单了:
bool member(Node *node, int x) { if (node->min == x || node->max == x) { return true; }else if (2 == node->u) { return false; }else return member(node->cluster[high(x, node->u)], low(x, node->u)); }
如果和最大或者最小相等那么肯定存在,而如果找到基结点去了,则不存在,如果不满足以上条件则继续往下查找。
接着便是前驱和后继:
int successor(Node *node, int x) { if (2 == node->u) { if (0 == x && 1 == node->max) { return 1; }else return NIL; }else if (NIL != node->min && x < node->min) { return node->min; }else { int max_low = max(node->cluster[high(x, node->u)]); if (NIL != max_low && low(x, node->u) < max_low) { int offset = successor(node->cluster[high(x, node->u)], low(x, node->u)); return index(high(x, node->u), offset, node->u); }else { int succ_cluster = successor(node->summary, high(x, node->u)); if (NIL == succ_cluster) { return NIL; }else { int offset = min(node->cluster[succ_cluster]); return index(succ_cluster, offset, node->u); } } } } int predecessor(Node *node, int x) { if (2 == node->u) { if (1 == x && 0 == node->min) { return 0; }else return NIL; }else if (NIL != node->max && x > node->max) { return node->max; }else { int min_low = min(node->cluster[high(x, node->u)]); if (NIL != min_low && low(x, node->u) > min_low) { int offset = predecessor(node->cluster[high(x, node->u)], low(x, node->u)); return index(high(x, node->u), offset, node->u); }else { int pred_cluster = predecessor(node->summary, high(x, node->u)); if (NIL == pred_cluster) { if (NIL != node->min && x > node->min) { return node->min; }else return NIL; }else { int offset = max(node->cluster[pred_cluster]); return index(pred_cluster, offset, node->u); } } } }
都是先在当前cluster中查找,如果当前cluster中查找不到,则到它的前一个或者后一个有数据中的结点中去查找。这里,唯一需要注意的地方就是,前驱判断的时候,当前结点不存在,在它的前一个结点中如果也没有找到有结点的数据的话,要注意还要判断是否有最小结点,如果有的话,这个也需要判断一下。
void insert(Node *node, int x) { if (NIL == node->min) { emptyInsert(node, x); }else { if (x < node->min) { int tmp = x; x = node->min; node->min = tmp; } if (node->u > 2) { if (NIL == min(node->cluster[high(x, node->u)])) { insert(node->summary, high(x, node->u)); emptyInsert(node->cluster[high(x, node->u)], low(x, node->u)); }else { insert(node->cluster[high(x, node->u)], low(x, node->u)); } } if (node->max < x) { node->max = x; } } }
插入操作的话,如果当前结点没有结点的话,则直接赋值最小和最大结点值就好了。或者的话,则需要和最小值比较,并且根据插入的值查找适合的cluster插入并且根据修改summary记录当中cluster的值。插入完成以后在判断是否需要修改最大值。
删除操作的话相对复杂一些:
void vBEDelete(Node *node, int x) { if (node->min == node->max) { node->min = NIL; node->max = NIL; }else if (2 == node->u) { if (0 == x) { node->min = 1; }else { node->min = 0; } node->max = node->min; }else { if (x == node->min) { int first_cluster = min(node->summary); x = index(first_cluster, min(node->cluster[first_cluster]), node->u); node->min = x; } vBEDelete(node->cluster[high(x, node->u)], low(x, node->u)); if (NIL == min(node->cluster[high(x, node->u)])) { vBEDelete(node->summary, high(x, node->u)); if (x == node->max) { int summary_max = max(node->summary); if (NIL == summary_max) { node->max = node->min; }else { node->max = index(summary_max, max(node->cluster[summary_max]), node->u); } } }else if (x == node->max) { node->max = index(high(x, node->u), max(node->cluster[high(x, node->u)]), node->u); } } }
如果是一个结点,则直接删除,如果是基结点,则修改最小和最大值为另一个结点。否则的话,往下遍历x结点所在的位置,如果需要删除的是最小结点,则直接重新找过一个最小结点,然后在cluster当中删除它。然后,判断cluster是否为空,如果为空的话,我们修改修改记录在summary当中的cluster信息并且修改最大值。或者,设置重新设置最大值。
我们测试下:
#include <iostream> #include <assert.h> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { static const int default_u = 16; init(default_u); insert(g_VEB->root, 2); assert(true == member(g_VEB->root, 2)); insert(g_VEB->root, 3); assert(true == member(g_VEB->root, 3)); insert(g_VEB->root, 4); assert(true == member(g_VEB->root, 4)); insert(g_VEB->root, 5); assert(true == member(g_VEB->root, 5)); insert(g_VEB->root, 7); assert(true == member(g_VEB->root, 7)); insert(g_VEB->root, 14); assert(true == member(g_VEB->root, 14)); insert(g_VEB->root, 15); assert(true == member(g_VEB->root, 15)); assert(14 == predecessor(g_VEB->root, 15)); assert(15 == successor(g_VEB->root, 14)); vBEDelete(g_VEB->root, 2); assert(false == member(g_VEB->root, 2)); vBEDelete(g_VEB->root, 3); assert(false == member(g_VEB->root, 3)); vBEDelete(g_VEB->root, 4); assert(false == member(g_VEB->root, 4)); vBEDelete(g_VEB->root, 5); assert(false == member(g_VEB->root, 5)); vBEDelete(g_VEB->root, 7); assert(false == member(g_VEB->root, 7)); vBEDelete(g_VEB->root, 14); assert(false == member(g_VEB->root, 14)); vBEDelete(g_VEB->root, 15); assert(false == member(g_VEB->root, 15)); finit(); return 0; }
这里内容没有释放,需要自己去释放。
结果如下:
没有任何错误信息输出。