Algorithm Search⌘K

Proofs: Quadtree

These are the human proofs of Quadtree, at full length.

The PR quadtree operations keep the compact invariant and answer window and nearest queries exactly full

This proof shows: correctness, termination.

We use the names of the pseudocode. The root cell is [0,2D)2[0, 2^D)^2, cells are half-open squares, and points have integer coordinates. For a node uu let S(u)S(u) be the set of points stored in the leaves below uu. The invariant (Q) asks: (1) each point of the tree lies in the cell of its leaf and is stored once; (2) each leaf holds at most BB points; (3) each internal node has u.count=∣S(u)∣>Bu.count = |S(u)| > B, and each leaf has u.count=∣u.points∣u.count = |u.points|; and (4) the children of an internal node of side ss are its four quadrants, of side s/2s/2.

Lemma 1 (quadrants). For a cell ZZ of side s≥2s \ge 2, the four quadrants are disjoint, their union is ZZ, and the quadrant chosen for p∈Zp \in Z is the one that holds pp. Proof. On each axis, [c,c+s)[c, c + s) is the disjoint union of [c,c+s/2)[c, c + s/2) and [c+s/2,c+s)[c + s/2, c + s), and the test pi≥c+s/2p_i \ge c + s/2 picks the half that holds pip_i. The product of the halves on the two axes gives the claim. □\square

Lemma 2 (unit cells). A cell of side 1 holds at most one integer point. Proof. It is [a,a+1)×[b,b+1)[a, a+1) \times [b, b+1) with integers a,ba, b, and the only integer point in it is (a,b)(a, b). □\square

Search. By Lemma 1 and (Q) part 4, at each internal node the point pp lies in exactly one child cell, so exactly one leaf has a cell that holds pp, and line L1 (and line L12) reaches it in at most DD steps, since the side halves at each step. By (Q) part 1, pp is stored exactly when it is in that leaf's list.

INSERT. Let pp be a point of the root cell that is not stored. Lines L1 to L3 add pp to the only leaf whose cell holds it, and add 1 to the count of each node whose subtree now holds pp, so parts 1 and 3 hold. If ∣u.points∣≤B|u.points| \le B, the loop does not run and (Q) holds.

Otherwise the loop starts with a leaf uu that holds B+1≥2B + 1 \ge 2 points, all in its cell, while (Q) holds at every other node. By Lemma 2, the side of uu is at least 2, so line L5 can make the four quadrants. Line L6 moves each point into the quadrant that holds it (Lemma 1), with counts equal to the list sizes; now uu is internal with u.count=B+1>Bu.count = B + 1 > B, so parts 3 and 4 hold at uu. The children's lists add up to B+1B + 1 points, so at most one child holds more than BB. If none does, (Q) holds everywhere and the loop stops. If one does, it holds exactly B+1B + 1 points, all in its cell, and the loop continues with it in the same situation. The side halves at each pass and is at least 2 at each pass, so after at most DD passes the loop stops.

DELETE. Let pp be stored, let uu be its leaf, and let v1,…,vjv_1, \ldots, v_j be the path from the root down to the parent of uu. After line L13, pp is gone and the counts of uu and of each viv_i are one less, so all counts are correct and parts 1, 2 and 4 hold. Part 3 can fail only at the nodes viv_i, and only when vi.count=Bv_i.count = B now.

Line L14 treats vj,vj−1,…v_j, v_{j-1}, \ldots in turn. Claim: when it reaches viv_i, (Q) holds at every node except possibly v1,…,viv_1, \ldots, v_i, and all counts are correct. This holds for i=ji = j. If vi.count>Bv_i.count > B, then vi′.count≥vi.count>Bv_{i'}.count \ge v_i.count > B for each i′<ii' < i, because the count of a node is at least the count of each child, so (Q) holds everywhere and the loop may stop. If vi.count≤Bv_i.count \le B, each child cc of viv_i has c.count≤Bc.count \le B; by the claim, part 3 holds at cc, so cc is a leaf. Line L14 gathers the lists of the four leaves, at most BB points in total, all in the cell of viv_i by part 1 and Lemma 1, into one leaf with the same count. Parts 1 to 4 then hold at viv_i, and the claim holds for i−1i - 1. The loop makes at most j≤Dj \le D steps.

Uniqueness. Let T(Z,S)\mathcal{T}(Z, S) be a tree on a set SS of points of the cell ZZ that satisfies (Q). If ∣S∣≤B|S| \le B, part 3 forces a leaf with list SS. If ∣S∣>B|S| > B, part 3 forces an internal root, part 4 fixes its children as the quadrants ZkZ_k, and by part 1 and Lemma 1 the child for ZkZ_k is a tree on S∩ZkS \cap Z_k that satisfies (Q). By induction on the side, it is unique. So the shape depends only on SS.

RANGE-SEARCH. Let W=[ℓx,hx]×[ℓy,hy]W = [\ell_x, h_x] \times [\ell_y, h_y]. Each reported point is stored and is in WW by the test of line L10, and the calls follow the tree, so each leaf is reached at most once, and by part 1 no point is reported twice. Let p∈S∩Wp \in S \cap W, with leaf ww. For each node vv on the path from the root to ww, the cells along the path are nested, so pp lies in the cell of vv and in WW; the cell of vv meets WW, and line L9 does not stop the search at vv. Line L11 calls every child, so the search reaches ww, and line L10 reports pp. The calls follow a finite tree, so the search stops.

NEAREST. Write δ(u)=dist⁡(q,cell of u)\delta(u) = \operatorname{dist}(q, \text{cell of } u). For each point pp below uu, pp is in the cell of uu, so ∥q−p∥≥δ(u)\lVert q - p \rVert \ge \delta(u). For a child cc of uu, the cell of cc is inside the cell of uu, so δ(c)≥δ(u)\delta(c) \ge \delta(u). Hence the keys extracted at line L18 never decrease: a key inserted at line L21 is at least the key just extracted, and the queue returns the smallest key.

Let p∗p^* be a stored point closest to qq, and suppose the loop ends with bestbest farther than p∗p^*, or with bestbest = none. The tree is not empty, so the root has count at least 1. Call a node processed when it was extracted and passed the test of line L19. The root is inserted at line L16, and each processed internal node inserts all its children with a nonzero count. Let aa be the deepest node on the path from the root to the leaf of p∗p^* that was inserted into the queue. If aa was processed and is a leaf, line L20 compared p∗p^* with bestbest, and bestbest is at least as close as p∗p^* from then on, a contradiction. If aa was processed and is internal, its child on the path to p∗p^* has a nonzero count and was inserted, against the choice of aa. So aa was never processed. The loop then ended at line L19 with an extracted key d≥∥q−best∥d \ge \lVert q - best \rVert, while aa was in the queue or was the node just extracted. Since dd was the smallest key, δ(a)≥d≥∥q−best∥>∥q−p∗∥≥δ(a)\delta(a) \ge d \ge \lVert q - best \rVert > \lVert q - p^* \rVert \ge \delta(a), a contradiction. If bestbest = none at the end, the loop stopped because the queue was empty, so aa was processed, and the cases above apply. Hence NEAREST returns a closest stored point. Each node is inserted at most once, so the loop stops. ■\blacksquare

Back to Quadtree