Algorithm Search⌘K

Proofs: van Emde Boas layout

These are the human proofs of van Emde Boas layout, at full length.

The van Emde Boas layout is a bijection with contiguous subtrees, and the search finds the predecessor full

This proof shows: correctness, termination.

We use the pseudocode of the page. A tree with h≥1h \ge 1 levels has the nodes (d,p)(d, p) with 0≤d<h0 \le d < h and 0≤p<2d0 \le p < 2^d; let S(h)=2h−1S(h) = 2^h - 1 be their number. For d≥td \ge t, the first tt bits of a dd-bit path pp are ⌊p/2d−t⌋\lfloor p / 2^{d-t} \rfloor and the last d−td - t bits are p mod 2d−tp \bmod 2^{d-t}.

Lemma 1 (V1 and V2). For every h≥1h \ge 1, the map (d,p)↦POS(h,d,p)(d, p) \mapsto \mathrm{POS}(h, d, p) is a bijection from the nodes of the tree with hh levels onto {0,…,S(h)−1}\{0, \ldots, S(h) - 1\}. Moreover, in the recursion of POS, the nodes of the top tree map onto {0,…,S(ht)−1}\{0, \ldots, S(h_t) - 1\} and the nodes of bottom tree jj onto the range {S(ht)+jS(hb),…,S(ht)+(j+1)S(hb)−1}\{S(h_t) + j S(h_b), \ldots, S(h_t) + (j+1) S(h_b) - 1\}, so each recursive subtree occupies a contiguous range.

Proof. By induction on hh. For h=1h = 1 there is one node, and line L1 maps it to 0. Let h≥2h \ge 2, ht=⌊h/2⌋≥1h_t = \lfloor h/2 \rfloor \ge 1 and hb=h−ht≥1h_b = h - h_t \ge 1; both are less than hh. The nodes with d<htd < h_t form a tree with hth_t levels, whose node (d,p)(d, p) is the same pair, and line L3 maps them by POS(ht,⋅,⋅)\mathrm{POS}(h_t, \cdot, \cdot), a bijection onto {0,…,S(ht)−1}\{0, \ldots, S(h_t) - 1\} by induction. The nodes with d≥htd \ge h_t split by their first hth_t bits j∈{0,…,2ht−1}j \in \{0, \ldots, 2^{h_t} - 1\} into 2ht2^{h_t} trees; in tree jj, the node (d,p)(d, p) corresponds to the node (d−ht,p mod 2d−ht)(d - h_t, p \bmod 2^{d - h_t}) of a tree with hbh_b levels, and this correspondence is a bijection. Line L5 maps it to S(ht)+jS(hb)+POS(hb,d−ht,p mod 2d−ht)S(h_t) + j S(h_b) + \mathrm{POS}(h_b, d - h_t, p \bmod 2^{d-h_t}), which by induction runs over the range stated, bijectively. The ranges for j=0,…,2ht−1j = 0, \ldots, 2^{h_t} - 1 are disjoint, follow each other, and follow the range of the top tree. Their union is {0,…,S(ht)+2htS(hb)−1}\{0, \ldots, S(h_t) + 2^{h_t} S(h_b) - 1\}, and S(ht)+2ht(2hb−1)=2ht−1+2h−2ht=S(h)S(h_t) + 2^{h_t}(2^{h_b} - 1) = 2^{h_t} - 1 + 2^h - 2^{h_t} = S(h). So POS is a bijection onto {0,…,S(h)−1}\{0, \ldots, S(h) - 1\}. The parts are contiguous at this level, and by induction inside each part. □\square

POS ends: each call is on a tree with fewer levels.

Lemma 2 (V3). After BUILD, the node (d,p)(d, p) holds the key of in-order rank r(d,p)=p⋅2h−d+2h−d−1−1r(d, p) = p \cdot 2^{h-d} + 2^{h-d-1} - 1 in the padded list, and the tree is a binary search tree with these keys.

Proof. In a complete binary tree with hh levels, the subtree of (d,p)(d, p) has 2h−d−12^{h-d} - 1 nodes, and the subtrees of the pp nodes to its left at depth dd, together with the ancestors between them, account for the first p⋅2h−dp \cdot 2^{h-d} ranks; the left subtree of (d,p)(d, p) has 2h−d−1−12^{h-d-1} - 1 nodes. So its in-order rank is r(d,p)r(d, p). Line L7 writes, by Lemma 1 at a distinct cell for each node, the padded key of that rank. Since the padded list is increasing, with +∞+\infty at the end, all keys in the left subtree of a node have smaller ranks, so they are smaller, and all keys in the right subtree are larger, with the convention that +∞+\infty is larger than every key and the cells of +∞+\infty are compared as +∞+\infty. □\square

Lemma 3. PREDECESSOR(k)(k) returns the largest key at most kk, or none if there is none.

Proof. Let PP be the set of real keys at most kk, and π\pi its largest element if PP is not empty. We keep the invariant: at the start of each pass of line L9, either π\pi is bestbest, or π\pi is in the subtree of the current node (d,p)(d, p), or PP is empty and bestbest is none; and bestbest is none or a key at most kk.

At the start, the current node is the root, whose subtree holds all keys, and bestbest is none.

Let xx be the key at the current node, read in line L10 at its position, which is right by Lemmas 1 and 2. If x=kx = k, then π=k\pi = k, and line L11 returns it. If x<kx < k, then x∈Px \in P, all keys in the left subtree are smaller than xx, so π\pi is xx or in the right subtree. Line L12 sets best←xbest \leftarrow x and moves to the right child; if π\pi is in the right subtree the invariant holds by the second case, and otherwise π=x=best\pi = x = best. If x>kx > k (including x=+∞x = +\infty), every key in the right subtree is larger than xx, so larger than kk; so if π\pi was in the subtree of the current node, it is in the left subtree, and line L12 moves there. In all cases the invariant holds.

The loop ends after at most hh passes, since dd grows by one each time (line L13). When d=hd = h, the current subtree is empty, so either π=best\pi = best or PP is empty and bestbest is none, and line L14 returns the right answer. And bestbest only ever takes values x<kx < k that are keys, by line L12. □\square

By Lemma 3, contains(k) is right, since kk is in the set exactly when its predecessor is kk. The I/O bound of a search follows from Lemma 1 (each recursive subtree is contiguous) by the argument on the cache-oblivious model page. ■\blacksquare

Back to van Emde Boas layout