Van Emde Boas树

van Emde Boas树（或称vEB树或van Emde Boas优先队列）是一个在电脑科学中的资料结构，也是一种关联阵列，也是一种树，由荷兰电脑科学家 Peter van Emde Boas领导的团队于 1975 年发明，可以储存键值范围在 m 位以内的二进制整数，也就是 formula_1 是树中可以储存的最大数字时，它可以在 formula_2 时间内执行所有种类的基本操作（假设对 formula_3 的位元操作可以在常数时间内执行），也就是 formula_4时间。参数formula_5不要与树中储存的实际元素数量混淆，其他树资料结构的效能通常透过该数量来衡量。 标准vEB树的空间效率不够。例如，用于储存 32 位元整数（即当 formula_6 ），它需要 formula_7 个储存位。然而，具有相似的时间效率和空间效率的资料结构可以使用 formula_8 空间（当 𝑛 是储存元素的数量），但是也可以修改vEB树让它只需要 formula_9 空间。
结构总览.
一棵 vEB 树的每个节点包含以下资料：
值得注意的是，若 formula_16 是最小元素，直接记录在，不会被记录在其他地方。
若节点为空，设定 ，所有找寻操作遇 都视作「不存在」，部分实作会采用 和 来代替。
表示法.
在后续的演算法描述中，我们会用到以下函数，设整体键值范围为 formula_5，定义:
说明：
可以观察到：
formula_30。
基本操作.
以下为vEB 树支援的一些操作:
插入.
将值 插入到 vEB 树 的操作 过程如下：
程式码如下:
 function Insert(T, x)
 if T.min == x || T.max == x then "// x 已经被插入了"
 return
 if T.min == NIL then "// T 是空树"
 T.min = T.max = x; 
 return
 if x &lt; T.min then
 swap(x, T.min) "// 更新最小点，插入旧的最小点"
 if x &gt; T.max then
 T.max = x "// 更新最大点"
 i = high(x)
 Insert(T.cluster[i], low(x))
 if T.cluster[i].min == T.cluster[i].max then
 Insert(T.summary, i)
 end
此过程的效率关键在于，将元素插入到空的 vEB 树只需 formula_31 时间，然后在大小为 formula_32（即 formula_33 位二进制数）的子树上递回处理。因此，即使算法有时会进行两次递回调用，这仅在第一次递回调用进入空子树时发生。可以得出这运行时间的递回关系是 formula_34，其解为 formula_35。
查询后继.
查询后继的过程如下：
程式码如下:
 function FindNext(T, x)
 if x &lt; T.min then
 return T.min
 if x ≥ T.max then "// 无后继数"
 return u
 i = high(x)
 if low(x) &lt; T.cluster[i].max then "// 后继在这个簇中"
 return index(i,FindNext(T.cluster[i], low(x))) 
 j = FindNext(T.summary, i) "// 后继在其他簇，搜寻辅助vEB树"
 if j == NIL then "// 检查是否存在后继簇"
 return NIL
 else
 return index(j, T.cluster[j].min) "// 与高位合并"
 end
注意，在任何情况下，这个函式本身执行 formula_31 的工作，然后可能在大小为 formula_32 的簇上递回处理。和之前的递推关系一样，所以复杂度仍是 formula_35。
查询前驱.
查询前驱和查询后继的方式大致相似，只有部分地方修改，重点在 也有可能是前驱，但不在子树的任何地方。
 function FindPrev(T, x)
 if x &gt; T.max then
 return T.max
 if x ≤ T.min then "// 无前驱数"
 return NIL
 i = high(x)
 if low(x) &gt; T.cluster[i].min then "// 前驱在这个簇"
 s = FindPrev(T.cluster[i], low(x))
 if s == NIL then "// 前驱在T.min"
 return T.min
 return index(i,s) "// 与高位合并"
 j = FindPrev(T.summary, i) "// 前驱在其他子树，搜寻辅助vEB树"
 if j == NIL then "// 检查是否存在前驱子树"
 return NIL
 else
 return index(j, T.cluster[j].max) "// 与高位合并"
 end
删除.
从vEB树中删除节点是最复杂的操作。呼叫 来删除vEB树T中的值"x"，其运作方式如下：
在上述任何情况下，如果我们从子树 中删除最后一个元素"x"或"y"，则还需要从 中删除"i"。
程式码如下:
 function Delete(T, x)
 // 删除最后一个元素
 if T.min == T.max == x then 
 T.min = NIL // 标记空树
 T.max = NIL 
 return
 // 删除当前最小值
 if x == T.min then 
 j = T.summary.min // 通过辅助树找最小簇索引
 T.min = x = index(j, T.cluster[j].min) // 新min = 树中存在的最小值
 Delete(T.cluster[j], T.cluster[j].min) // 从子树中删除，因为T.min不应在子树中出现
 return
 // 分解高位和低位
 i = high(x) // 计算簇索引
 // 递回删除
 Delete(T.cluster[i], low(x)) 
 // 处理空子树
 if T.cluster[i] is empty then 
 Delete(T.summary, i) // 从辅助树删除该子树索引
 // 删除的是当前最大值
 if x == T.max then
 if T.summary is empty then // 没有其他子树
 T.max = T.min // 只剩min值
 else
 j = T.summary.max //找最大值
 T.max = index(j, T.cluster[j].max) // 合并
 end
同样，此程序的效率取决于从仅包含一个元素的vEB树中删除只需 formula_31 时间。特别是，只有在删除前 "x" 是 中唯一元素时，才会递回删除 中对应的元素。
实际实现.
实际上并不需要假设 formula_42 必须是整数。运算 和 可以分别替换为只取 x 的高位 formula_43 位元和低位 formula_44 位元。在大部分情况下，这都比除法或取余运算更高效。
在实际实现中，特别是在具有「位移 k 位」和「寻找首位零」指令的机器上，当 m 达到字长（或其小倍数）时，可以切换为使用位阵列来进一步提升效能。由於单一字长上的所有操作都是常数时间，这不会影响渐进效能，但能避免多数指标储存和多次指标解引用，从而显著节省实际的时间和空间。
vEB 树的一个优化是舍弃空子树。这使得 vEB 树在包含大量元素时非常紧凑，因为只有在需要添加元素时才会创建子树。最初，每添加一个元素会创建约 formula_45 个新树，总共包含约 formula_33 个指标。随著树的增长，越来越多的子树会被重复使用，尤其是较大的子树。
上述实现使用指标，并占用总空间 formula_47，与键值空间的大小成正比。这可以通过以下方式理解：递回关系为 formula_48。解此递回关系会得到 formula_49。也可以通过数学归纳法证明 formula_50。