Algorithm Search⌘K

Proofs: Eytzinger layout

These are the human proofs of Eytzinger layout, at full length.

The Eytzinger lower bound search returns the slot of the first item not less than x, or 0 full

This proof shows: correctness, termination, complexity.

Let B[1…n]B[1 \ldots n], n≥0n \ge 0, be built by EYTZINGER-BUILD from a sorted array A[0…n−1]A[0 \ldots n-1]. The implicit tree has the slots 1,…,n1, \ldots, n, and slot kk has the children 2k2k and 2k+12k + 1 when they are at most nn. For a slot kk, write π(k)\pi(k) for its position in the in-order walk (left subtree, node, right subtree) from the root. Let xx be a key and ℓ=∣{j:A[j]<x}∣\ell = |\{j : A[j] < x\}|.

The build. FILL visits the slots in in-order and writes A[0],A[1],…A[0], A[1], \ldots in that order, so B[k]=A[π(k)]B[k] = A[\pi(k)] and R[k]=π(k)R[k] = \pi(k). Hence items in in-order are sorted, and the slot with π(k)=ℓ\pi(k) = \ell, when ℓ<n\ell < n, holds the lower bound of xx. We prove that EYTZINGER-LOWER-BOUND returns that slot when ℓ<n\ell < n and 0 when ℓ=n\ell = n.

In-order facts. For a slot kk, every slot in the left subtree of kk has a smaller π\pi than kk, and every slot in the right subtree a larger one. Since B[k]=A[π(k)]B[k] = A[\pi(k)] and AA is sorted, π(k)<ℓ\pi(k) < \ell holds exactly when B[k]<xB[k] < x.

The walk. Let k0=1,k1,…,khk_0 = 1, k_1, \ldots, k_h be the values of kk at the tests of line L9, so k0,…,kh−1≤nk_0, \ldots, k_{h-1} \le n and kh>nk_h > n, and let ct=[B[kt]<x]c_t = [B[k_t] < x], so kt+1=2kt+ctk_{t+1} = 2k_t + c_t. The walk stops: kk at least doubles in each pass, so h≤⌊lg⁡n⌋+1h \le \lfloor \lg n \rfloor + 1. Each kt+1k_{t+1} with t+1<ht + 1 < h is a child of ktk_t, so k0,…,kh−1k_0, \ldots, k_{h-1} is a path from the root; and khk_h is the number of a missing child of kh−1k_{h-1}. If n=0n = 0 then h=0h = 0, k0=1k_0 = 1, and the result below is 0, which is correct.

Claim. Let SS be the set of steps t<ht < h with ct=0c_t = 0. If SS is empty then ℓ=n\ell = n. Otherwise, with s=max⁡Ss = \max S, π(ks)=ℓ\pi(k_s) = \ell.

Proof of the claim. Every slot qq of the tree is either some ktk_t with t<ht < h, or lies in the subtree of the child of some ktk_t that the walk did not take; for t=h−1t = h - 1 the walk leaves the tree, so the other child of kh−1k_{h-1} is the only one not taken there. Take such a qq.

  • If q=ktq = k_t with ct=1c_t = 1, then π(q)<ℓ\pi(q) < \ell.
  • If qq is in the left subtree of ktk_t and the walk went right at ktk_t (ct=1c_t = 1), then π(q)<π(kt)<ℓ\pi(q) < \pi(k_t) < \ell.
  • If q=ktq = k_t with ct=0c_t = 0, then π(q)≥ℓ\pi(q) \ge \ell.
  • If qq is in the right subtree of ktk_t and the walk went left (ct=0c_t = 0), then π(q)>π(kt)≥ℓ\pi(q) > \pi(k_t) \ge \ell.

So the slots with π≥ℓ\pi \ge \ell are exactly the nodes ktk_t with t∈St \in S and the right subtrees of those nodes. If SS is empty, no slot has π≥ℓ\pi \ge \ell, so ℓ=n\ell = n. Otherwise, let s=max⁡Ss = \max S. For t∈St \in S with t<st < s, the walk went left at ktk_t, so ksk_s is in the left subtree of ktk_t, and so is the right subtree of ksk_s; hence π(ks)<π(kt)\pi(k_s) < \pi(k_t) and π(ks)\pi(k_s) is less than every π\pi in the right subtree of ktk_t. Also every slot in the right subtree of ksk_s has π>π(ks)\pi > \pi(k_s). So ksk_s has the smallest π\pi among the slots with π≥ℓ\pi \ge \ell. Since π\pi takes every value 0,…,n−10, \ldots, n - 1 once and the slots with π≥ℓ\pi \ge \ell are those with π∈{ℓ,…,n−1}\pi \in \{\ell, \ldots, n-1\}, this smallest value is ℓ\ell. □\square

The bits. By kt+1=2kt+ctk_{t+1} = 2k_t + c_t and k0=1k_0 = 1, the binary form of khk_h is 1 c0 c1⋯ch−11\, c_0\, c_1 \cdots c_{h-1}, and the binary form of ksk_s is 1 c0⋯cs−11\, c_0 \cdots c_{s-1}. If SS is empty, kh=2h+1−1k_h = 2^{h+1} - 1 has all its h+1h + 1 bits equal to 1, so it has t=h+1t = h + 1 trailing 1 bits, and line L11 gives kh>>(h+2)=0k_h >> (h + 2) = 0. If SS is not empty, the bits after cs=0c_s = 0 are all 1, since ss is the last left turn, so khk_h has exactly t=h−1−st = h - 1 - s trailing 1 bits, preceded by the 0 bit csc_s. Shifting right by t+1=h−st + 1 = h - s removes cs,…,ch−1c_s, \ldots, c_{h-1} and leaves 1 c0⋯cs−1=ks1\, c_0 \cdots c_{s-1} = k_s.

With the claim, line L12 returns ksk_s, the slot with π(ks)=ℓ\pi(k_s) = \ell, when ℓ<n\ell < n, and 0 when ℓ=n\ell = n.

The count. The walk makes hh comparisons, where h=⌊lg⁡kh⌋h = \lfloor \lg k_h \rfloor is the depth of the external position khk_h. Since n<kh≤2n+1n < k_h \le 2n + 1, we get ⌊lg⁡(n+1)⌋≤h≤⌊lg⁡(2n+1)⌋=⌊lg⁡n⌋+1=⌈lg⁡(n+1)⌉\lfloor \lg(n+1) \rfloor \le h \le \lfloor \lg(2n+1) \rfloor = \lfloor \lg n \rfloor + 1 = \lceil \lg(n+1) \rceil for n≥1n \ge 1. ■\blacksquare

Back to Eytzinger layout