Algorithm Search⌘K

Proofs: Radix heap

These are the human proofs of Radix heap, at full length.

The radix heap returns the minimum, and each item moves at most lg U times full

This proof shows: correctness, time.amortized.

Keys are nonnegative integers below U=2wU = 2^w. For an integer k≥lastk \ge last, let b(k)=0b(k) = 0 if k=lastk = last, and b(k)=1+⌊lg⁡(k⊕last)⌋b(k) = 1 + \lfloor \lg(k \oplus last) \rfloor otherwise. So for b(k)=i≥1b(k) = i \ge 1, the keys kk and lastlast agree on bits w−1,…,iw - 1, \dots, i and differ in bit i−1i - 1. The invariant is (R1): every key in the heap is at least lastlast, and (R2): every item with key kk is in B[b(k)]B[b(k)].

Lemma 1 (order of buckets). Under (R1) and (R2), every key in B[0]B[0] equals lastlast, and if 1≤i<j1 \le i < j, every key in B[i]B[i] is smaller than every key in B[j]B[j]. Also, every key in B[i]B[i] with i≥1i \ge 1 is larger than lastlast.

Proof. B[0]B[0] holds only keys with k⊕last=0k \oplus last = 0. Let k∈B[i]k \in B[i] with i≥1i \ge 1. Then k≠lastk \ne last, and kk and lastlast agree above bit i−1i - 1 and differ in it. Since k>lastk > last by (R1), bit i−1i - 1 is 1 in kk and 0 in lastlast. Now let k∈B[i]k \in B[i] and k′∈B[j]k' \in B[j] with 1≤i<j1 \le i < j. Both agree with lastlast on bits above j−1j - 1. On bit j−1j - 1, kk agrees with lastlast, which has a 0 there, while k′k' has a 1. So k<k′k < k'. □\square

Lemma 2 (refill). Let (R1) and (R2) hold, B[0]B[0] be empty, ii be the smallest index with B[i]B[i] not empty, and dd be the smallest key in B[i]B[i]. Then dd is the smallest key in the heap. After line L5 sets last←dlast \leftarrow d, (R1) holds; and for the new lastlast, every key of B[j]B[j] with j>ij > i still has b(k)=jb(k) = j, and every key kk of the old B[i]B[i] has b(k)<ib(k) < i.

Proof. By Lemma 1, the keys of B[i]B[i] are smaller than those of all higher buckets, and the lower buckets are empty. So dd is the minimum, and every key is at least dd, which is (R1).

Write ℓ\ell for the old lastlast. Since d∈B[i]d \in B[i], the key dd agrees with ℓ\ell on all bits above i−1i - 1, and has a 1 in bit i−1i - 1. Let k∈B[j]k \in B[j] with j>ij > i. Then kk agrees with ℓ\ell, and so with dd, on all bits above j−1j - 1, and differs from ℓ\ell in bit j−1j - 1. Since j−1>i−1j - 1 > i - 1, the bit j−1j - 1 of dd equals that of ℓ\ell, so kk differs from dd in bit j−1j - 1, and b(k)=jb(k) = j for the new lastlast.

Let kk be in the old B[i]B[i]. Then kk and dd both agree with ℓ\ell above bit i−1i - 1, and both have a 1 in bit i−1i - 1. So k⊕d<2i−1k \oplus d < 2^{i-1}, and b(k)≤i−1b(k) \le i - 1 for the new lastlast. □\square

Theorem 1 (correctness). INSERT and EXTRACT-MIN keep (R1) and (R2), and EXTRACT-MIN returns an item with the smallest key.

Proof. INSERT checks key(x)≥last\mathrm{key}(x) \ge last and puts xx in B[b(key(x))]B[b(\mathrm{key}(x))], so both conditions hold. In EXTRACT-MIN, if B[0]B[0] is not empty, its items have key lastlast, which is the minimum by (R1), and removing one keeps both conditions. Otherwise, by Lemma 2, the new lastlast is the minimum and (R1) holds. Lines L6 and L7 move every item of the old B[i]B[i] to its bucket for the new lastlast, and by Lemma 2 the items of higher buckets are already in theirs, so (R2) holds. The item with key dd has b(d)=0b(d) = 0, so B[0]B[0] is not empty, and line L8 returns an item of key d=lastd = last. □\square

Theorem 2 (moves). Each item is moved by line L7 at most ww times, so a sequence of nn inserts and any number of extract-mins does O(nlog⁡U)O(n \log U) moves in total.

Proof. By Lemma 2, a move takes an item from B[i]B[i] to a bucket with a smaller index, and an item in a higher bucket keeps its index. A change of lastlast is the only event that can change a bucket index, so the index of each item never grows. It starts at most at ww, the largest index for keys below 2w2^w, and it is never below 0. Each move lowers it by at least 1, so there are at most w=lg⁡Uw = \lg U moves per item. ■\blacksquare

The other work of an extract-min is the search of line L4, which takes O(w)O(w) time by a scan, or O(1)O(1) with a bit mask of nonempty buckets and an instruction for the lowest set bit. So with the mask, the total time of nn inserts and n′n' extract-mins is O((n+n′)+nlog⁡U)O((n + n') + n \log U): O(log⁡U)O(\log U) amortized per insert and O(1)O(1) amortized per extract-min.

Back to Radix heap