โ† Wiki Index / Computation & Algorithms / Van Emde Boas Tree
๐Ÿ’ป Computation & Algorithms

Van Emde Boas Tree

A van Emde Boas tree is a recursive universe-splitting data structure over bounded integer keys that performs search, insertion, deletion, predecessor, and successor operations in O(log log U) time.

Van Emde Boas tree (abbreviated vEB tree, and also known as a van Emde Boas priority queue) is a recursive associative array and ordered dictionary data structure within computation and algorithms that maintains a dynamic subset of integers drawn from a bounded universe {0, 1, โ€ฆ, U โˆ’ 1} in O(log log U) worst-case time per operation. Invented by Dutch computer scientist Peter van Emde Boas and colleagues in 1975 (and refined with Robert Kaas and E. Zijlstra in 1977), the structure bypasses the ฮฉ(log n) information-theoretic lower bound of comparison-based search trees such as redโ€“black trees and AVL trees by exploiting the bit representation of machine integers on a Word RAM processor.

When keys are w-bit integers (so U = 2w), a standard balanced binary search tree requires O(log n) โ‰ค O(w) steps per query. By recursively partitioning a universe of size U into โˆšU sub-universes (clusters) each of size โˆšU, alongside a single โˆšU-sized summary tree tracking which clusters are non-empty, a van Emde Boas tree halves the bit length w at every level of recursion. Performing only O(1) recursive calls of size โˆšU per operation satisfies the recurrence T(U) = T(โˆšU) + O(1), which resolves to O(log log U) = O(log w) time for Insert, Delete, Member, Predecessor, and Successor.

Recursive Universe Decomposition and Uncached Storage Layout

High/Low Bit Splitting Into โˆšU Clusters

Assume for simplicity that the universe size is a power of two of the form U = 22k (or more generally U = 2w, split into upper bits Uโ†‘ = 2โŒˆw/2โŒ‰ and lower bits Uโ†“ = 2โŒŠw/2โŒ‹). Every integer key x โˆˆ {0, 1, โ€ฆ, U โˆ’ 1} can be decomposed by bit-shifting into a high cluster index high(x) and a low intra-cluster offset low(x):

high(x) = โŒŠx / โˆšUโŒ‹, low(x) = x mod โˆšU, index(c, i) = c ยท โˆšU + i

A recursive node vEB(U) over universe size U > 2 maintains four structural components:

  1. min and max: Two integer fields storing the minimum and maximum elements currently present in the vEB(U) node (or NIL if the node is empty).
  2. cluster[0 .. โˆšU โˆ’ 1]: An array of โˆšU pointers to child structures vEB(โˆšU), where cluster[c] stores the values low(x) of all present elements x > min that have high(x) = c.
  3. summary: A single pointer to an auxiliary child structure vEB(โˆšU) that stores the set of cluster indices c โˆˆ {0, โ€ฆ, โˆšU โˆ’ 1} for which cluster[c] is currently non-empty.

At the base case vEB(2) (where U = 2), no child pointers are needed; the node stores only min and max โˆˆ {0, 1, NIL}, handling all operations in O(1) time.

The Lazy min Exclusion Invariant

If an operation performed two recursive calls of size โˆšU (for instance, recursing into cluster[c] and also recursing into summary), its runtime recurrence would be T(U) = 2 T(โˆšU) + O(1), which evaluates to O(2log log U) = O(log U)โ€”losing the doubly logarithmic speedup.

Van Emde Boas solved this bottleneck with a single structural invariant: the element stored in vEB.min is NOT stored recursively inside any child cluster[high(min)]. This invariant delivers two essential constant-time shortcuts:

  • Inserting into an empty node (vEB.min == NIL): Simply sets vEB.min โ† x and vEB.max โ† x in O(1) time without making any recursive calls.
  • Inspecting whether a cluster is empty or contains โ‰ฅ 1 element: Requires only an O(1) read of cluster[c].min and cluster[c].max.

Doubly Logarithmic Operations and Recurrence Proof

Insert, Successor, and Delete With a Single Recursive Call

Under the lazy min exclusion invariant, every dictionary operation makes at most one recursive call of size โˆšU that itself recurses deeper:

  • Insert(V, x):
    1. If V.min == NIL, set V.min โ† V.max โ† x and return in O(1) time.
    2. If x < V.min, swap x โ†” V.min (so the old minimum is pushed down into its cluster).
    3. Let c = high(x) and i = low(x). If V.cluster[c].min == NIL, then V.cluster[c] is currently empty: call Insert(V.summary, c) (which may take O(log log โˆšU) time), and then call Insert(V.cluster[c], i)โ€”which executes the empty-node base case in O(1) time! Conversely, if V.cluster[c].min != NIL, V.summary already contains c, so only Insert(V.cluster[c], i) is called. In either branch, at most one non-constant recursive call occurs.
  • Successor(V, x):
    1. If x < V.min, return V.min in O(1) time.
    2. Let c = high(x) and i = low(x). Check in O(1) time whether V.cluster[c] contains an element larger than i by testing i < V.cluster[c].max.
    3. Intra-cluster case (i < V.cluster[c].max): The successor lies inside cluster c; recursively compute j = Successor(V.cluster[c], i) and return index(c, j).
    4. Inter-cluster case (i โ‰ฅ V.cluster[c].max): The successor lies in the next non-empty cluster; recursively compute c' = Successor(V.summary, c) and return index(c', V.cluster[c'].min) in O(1) additional time because the minimum of cluster c' is stored directly in V.cluster[c'].min!
  • Delete(V, x): Symmetrically, when deleting the last remaining element inside V.cluster[c] (which takes O(1) time because min == max), the algorithm makes one recursive call Delete(V.summary, c) to remove c from the summary; when V.cluster[c] still has remaining elements, V.summary is untouched and only Delete(V.cluster[c], i) recurses.

Substituting w = log2 U into T(2w) = T(2w/2) + O(1) gives S(w) = S(w/2) + O(1), which evaluates to O(log w) = O(log log U) worst-case time per operation.

Integer / Ordered DictionarySearch / PredecessorInsert / DeleteSpace ComplexityWord-Length / Key Assumption
Standard vEB Tree (1975)O(log log U)O(log log U)O(U)Bounded integers in [0, U โˆ’ 1]
Hash-Backed vEB / x-fast & y-fast TrieO(log log U)O(log log U) amort.O(n)w-bit integers + hash tables + BST
Fusion Tree (Fredman & Willard, 1993)O(logw n)O(logw n)O(n)Word-level parallel B-tree node sketching
Redโ€“Black / AVL / B-TreeO(log n)O(log n)O(n)Arbitrary comparable keys
Roaring Bitmap (2016)O(1) / O(log k)O(1) / O(k)Compressed O(n)32-bit / 64-bit integer sets

Linear-Space Reductions: Hash-Backed vEB Trees and y-fast Tries

Overcoming the O(U) Space Bottleneck

A naive van Emde Boas tree allocates all โˆšU child cluster pointers eagerly at construction time, satisfying the space recurrence M(U) = (โˆšU + 1) M(โˆšU) + O(โˆšU) = O(U). When U = 264 or even 232 with a sparse set of n โ‰ช U elements, allocating O(U) memory is prohibitive. Two structural refinements reduce the space requirement from O(U) to O(n):

  1. Hash-Table Cluster Indirection: Replace the fixed array cluster[0 .. โˆšU โˆ’ 1] in each node with a dynamic hash table that stores entries (c, pointer) only for non-empty clusters, allocating vEB(โˆšU) subtrees lazily when a second element enters a cluster. Because each element x โˆˆ S is stored as the min field of exactly one node in the tree, at most n cluster nodes are ever created, reducing space to O(n) (or O(n log log U) without bottom-level indirection) with O(log log U) expected time.
  2. Willard's x-fast and y-fast Tries (1983): Dan Willard introduced the x-fast trie (a binary trie over the w-bit prefixes of keys augmented with level hash tables, using O(n log U) space) and the y-fast trie, which groups consecutive keys into balanced binary search tree buckets of size ฮ˜(log U) and stores only O(n / log U) representative splitters in a top-level x-fast trieโ€”achieving O(n) space and O(log log U) time.

Network IP Routing and High-Speed Event Scheduling

In high-throughput Internet backbone routers, longest-prefix matching on 32-bit IPv4 and 128-bit IPv6 routing tables is equivalent to a predecessor query over integer interval endpoints. Van Emde Boas trees and x-fast/y-fast tries reduce per-packet lookup latency from 32 or 128 binary trie steps down to 5 or 7 hash probes. Similarly, substituting a van Emde Boas priority queue into Dijkstra's algorithm or Prim's algorithm over integer edge weights in {0, โ€ฆ, C} reduces shortest-path and minimum spanning tree complexity to O((V + E) log log U).

Frequently Asked Questions

Why does a van Emde Boas tree not violate the ฮฉ(n log n) sorting lower bound?

The ฮฉ(n log n) sorting lower bound (and the corresponding ฮฉ(log n) dictionary search lower bound) applies only to the algebraic decision-tree model, where algorithms may only compare pairs of keys using <, =, and >. A van Emde Boas tree operates in the Word RAM model, using the integer value of a key x directly as an array index and bit-field offset (x >> (w/2) and x & mask), which extracts w/2 bits of information in a single O(1) CPU instruction rather than 1 bit per comparison.

Why is min not stored recursively inside its cluster, whereas max is stored inside its cluster?

Excluding min from recursive storage allows inserting into an empty vEB node to finish in O(1) time, which prevents double recursion when a previously empty cluster is added to summary. Meanwhile, storing max both in the header field V.max and recursively inside its cluster ensures that Successor(V, x) can check whether x has a successor inside its own cluster in O(1) time via low(x) < V.cluster[high(x)].max, and that Predecessor(V, x) can jump directly to V.min when the predecessor is the minimum element of the node.

What is the PฤƒtraลŸcuโ€“Thorup lower bound for predecessor search?

Mihai PฤƒtraลŸcu and Mikkel Thorup (2006) proved that for any static or dynamic data structure occupying polynomial space nO(1) on a Word RAM with w-bit words, the optimal worst-case time for predecessor queries is ฮ˜(min(logw n, log(w / log w), โ€ฆ)). In particular, when w = ฮ˜(log n) (polynomial universe size U = nO(1)), the O(log log U) = O(log w) bound of a van Emde Boas tree is asymptotically optimal.

References

  1. van Emde Boas, P. (1975). "Preserving order in a forest in less than logarithmic time." In Proceedings of the 16th Annual Symposium on Foundations of Computer Science (SFCS 1975), 75โ€“84. https://doi.org/10.1109/SFCS.1975.26
  2. van Emde Boas, P., Kaas, R., & Zijlstra, E. (1977). "Design and implementation of an efficient priority queue." Mathematical Systems Theory, 10(1), 99โ€“127. https://doi.org/10.1007/BF01683268
  3. Willard, D. E. (1983). "Log-logarithmic worst-case range queries are possible in space ฮ˜(N)." Information Processing Letters, 17(2), 81โ€“84. https://doi.org/10.1016/0020-0190(83)90075-390075-3)
  4. PฤƒtraลŸcu, M., & Thorup, M. (2006). "Time-space trade-offs for predecessor search." In Proceedings of the Thirty-Eighth Annual ACM Symposium on Theory of Computing (STOC '06), 232โ€“240. https://doi.org/10.1145/1132516.1132551
๐Ÿงฌ Support Open Science
Explore interactive science games on LowKey Games or browse scientific apparel & accessories in the CRV Science Shop.
๐Ÿ’ก Spot an inaccuracy or have primary literature to expand this article?
Submit a citation or revision note using your shared CRV Science / LowKey Games profile ID.
Suggest Revision