Algorithm Search⌘K

Proofs: Persistent treap

These are the human proofs of Persistent treap, at full length.

The persistent treap keeps every version, and each version is a random treap full

This proof shows: correctness.

A treap on a finite set SS of keys with priorities p(k)p(k) is a binary tree whose nodes hold the keys of SS, once each, in search-tree order (I1) and in heap order on priorities (I2). For a node tt write keys(t)\text{keys}(t) for the set of keys in its subtree, with keys(nil)=∅\text{keys}(\text{nil}) = \emptyset. A tree whose size fields satisfy (I3) is called sized.

Lemma 1 (no change). No procedure writes a field of an existing node. Hence keys(t)\text{keys}(t) and the shape below tt never change once tt is made.

Proof. The procedures make nodes only by COPY and NEW-NODE, which write the fields of a node that did not exist before, and set the size from the children at that moment. CONTAINS only reads. □\square

Lemma 2 (split). If tt is a sized treap, then SPLIT(t,k)(t, k) returns sized treaps aa and bb with keys(a)={x∈keys(t):x<k}\text{keys}(a) = \{x \in \text{keys}(t) : x < k\} and keys(b)={x∈keys(t):x≥k}\text{keys}(b) = \{x \in \text{keys}(t) : x \ge k\}, and every priority of aa or bb is the priority of the same key in tt.

Proof. By induction on the size of tt. For nil, line L1 is right. If t.key<kt.key < k (line L2), then all of t.leftt.left and t.keyt.key belong to the part below kk, and by induction SPLIT(t.right,k)(t.right, k) splits the right subtree into aa and bb. The copy of tt with right child aa has t.keyt.key above all keys of t.leftt.left and below all keys of a⊆keys(t.right)a \subseteq \text{keys}(t.right), so it is in search order; its priority t.priot.prio is at least each priority in t.leftt.left and in aa, because those are priorities of the subtree of tt; so it is in heap order. Its size is set from its children. The tree bb is a treap by induction, and its keys are those of t.rightt.right at least kk, which are all the keys of tt at least kk. Line L3 is the mirror case. □\square

Lemma 3 (merge). If aa and bb are sized treaps with every key of aa less than every key of bb, then MERGE(a,b)(a, b) returns a sized treap on keys(a)∪keys(b)\text{keys}(a) \cup \text{keys}(b) with the same priorities.

Proof. By induction on ∣a∣+∣b∣|a| + |b|. Lines L4 and L5 are clear. If a.prio>b.prioa.prio > b.prio (line L6), then a.prioa.prio is the highest priority of both trees, so a.keya.key may be the root. By induction MERGE(a.right,b)(a.right, b) is a treap on the keys of a.righta.right and bb, all of which are above a.keya.key, and with priorities at most a.prioa.prio. So the copy of aa with this right child is a treap. Line L7 is the mirror case, using b.prio≥a.priob.prio \ge a.prio. □\square

Lemma 4 (insert). If tt is a sized treap and k∉keys(t)k \notin \text{keys}(t), then INS(t,k,p)(t, k, p) returns a sized treap on keys(t)∪{k}\text{keys}(t) \cup \{k\}, in which kk has priority pp and every other key has its old priority.

Proof. By induction on the size of tt. In line L10, either tt is nil, or p>t.priop > t.prio, so pp is higher than every priority of tt by heap order. By Lemma 2, SPLIT gives treaps aa and bb on the keys below and above kk, and the new node with key kk, priority pp and children aa and bb is in search order and heap order. Otherwise t.prio≥pt.prio \ge p, and kk goes to the side given by the search order (lines L11 and L12). By induction the new subtree is a treap on the old keys of that side plus kk, with priorities at most t.priot.prio (the old ones, and p≤t.priop \le t.prio). So the copy of tt with this child is a treap. □\square

Lemma 5 (delete). If tt is a sized treap and k∈keys(t)k \in \text{keys}(t), then DEL(t,k)(t, k) returns a sized treap on keys(t)∖{k}\text{keys}(t) \setminus \{k\} with the old priorities.

Proof. By induction on the size of tt. If k=t.keyk = t.key, line L17 merges t.leftt.left and t.rightt.right, whose keys are separated by kk; Lemma 3 applies. Otherwise kk lies in the subtree on the side chosen by line L15 or L16, which by induction is replaced by a treap on its keys minus kk, with priorities at most t.priot.prio; the copy of tt is a treap. □\square

Theorem 1 (persistence and correctness). After any sequence of operations, every version is a sized treap on the set that the abstract ordered set gives to it, and every query returns the abstract answer on its version.

Proof. By induction on the operations. The empty set is nil. INSERT returns tt unchanged when kk is present (line L8) and otherwise is right by Lemma 4. DELETE returns tt when kk is absent (line L13) and otherwise is right by Lemma 5. split and merge are right by Lemmas 2 and 3; merge checks its precondition. CONTAINS follows the search order, so by (I1) it finds kk if and only if kk is present. By Lemma 1 the earlier versions do not change. □\square

Theorem 2 (shape of a version). Suppose the sequence of operations, and the keys they use, is fixed in advance and does not depend on the priorities, and the priorities of new keys are independent and uniform on [0,1)[0, 1). Then for each version with key set SS, the priorities of the keys of SS are independent and uniform, and the tree of the version is the unique treap on SS with these priorities. Hence the expected depth of the key of rank ii in a version of nn keys is Hi+Hn−i+1−1H_i + H_{n-i+1} - 1.

Proof. A key in a version got its priority when it was inserted on the path of the version tree that leads to this version, and each priority is copied with its key and never changed (Lemmas 2 to 5 keep old priorities). Distinct keys of SS got their priorities in distinct calls of INSERT, so the priorities of SS are independent and uniform. With probability 1 they are distinct. A treap on a set with distinct priorities is unique: the key with the highest priority must be the root, and the two sides are treaps on the keys below and above it, unique by induction. So the version is the treap on SS with random priorities, which has the same distribution as an ephemeral treap on SS, and the depth formula of Seidel and Aragon holds. ■\blacksquare

Back to Persistent treap