Algorithm Search⌘K

Proofs: k-d-B tree

These are the human proofs of k-d-B tree, at full length.

The k-d-B tree keeps a balanced partition of the plane into page regions, and its operations are correct full

This proof shows: correctness, termination.

We use the names of the pseudocode. Regions are half-open boxes [lo,hi)[lo, hi), possibly unbounded, and the root's region is the plane. The invariant (K) asks: (1) the regions of the children of each region page partition its region; (2) each point lies in the region of its point page and is stored once; (3) all point pages are at the same depth; (4) a point page holds at most BB points and a region page between 1 and MM children. We also use (G): the children of each region page form a guillotine partition, that is, either there is one child, or some line xa=vx_a = v at a child boundary crosses no child and both sides are again guillotine partitions.

Lemma 1 (SPLIT). Let uu satisfy (K) and (G) below it, and let the line xa=vx_a = v have loa(u)<v<hia(u)lo_a(u) < v < hi_a(u). Then SPLIT(u,a,v)(u, a, v) returns two pages ℓ\ell and rr at the level of uu, with regions R(u)∩{xa<v}R(u) \cap \{x_a < v\} and R(u)∩{xa≥v}R(u) \cap \{x_a \ge v\}, such that (K) parts 1 to 3 and (G) hold below each, the points of uu are divided between them by the side of the line, and each has at most as many children as uu and at least one, if uu is a region page. Proof. By induction on the height of uu. For a point page, the two lists are the points on each side, and each lies in its half region. For a region page, each child cc lies left of the line (hia(c)≤vhi_a(c) \le v), right of it (loa(c)≥vlo_a(c) \ge v), or crosses it; a crossing child has loa(c)<v<hia(c)lo_a(c) < v < hi_a(c), and by induction it splits into two halves at its own level. The children of ℓ\ell are the left children and the left halves; their regions are the parts left of the line of the regions of the children of uu, which partition R(u)∩{xa<v}R(u) \cap \{x_a < v\}, so part 1 holds. Part 3 holds since every half is at the level of the page it came from. Each child of uu gives at most one child to each side, so neither side has more than uu. The region of uu has points on both sides of the line, so some child of uu meets each side, and each side has a child. For (G), a guillotine partition cut by a line gives a guillotine partition on each side: cut the tree of cuts by the line, and remove the cuts that fall outside. □\square

Lemma 2 (a cut exists). Let a region page uu have M+1≥3M + 1 \ge 3 children in a guillotine partition. Then some line at a child boundary leaves at most MM entries on each side, counting each crossed child on both sides. Proof. By (G) there is a line that crosses no child, with both sides nonempty; its sides have LL and RR children with L+R=M+1L + R = M + 1 and L,R≥1L, R \ge 1, so L,R≤ML, R \le M. It is at a child boundary vv with v>loa(u)v > lo_a(u). □\square

So line L5 always finds a cut for a region page; for a point page with B+1B + 1 distinct points, the points differ on some axis, and the median vv of the m≥2m \ge 2 distinct values on it has a value below it, so both sides of xa=vx_a = v get a point.

Search. By part 1 and induction, for each point pp and each level, exactly one page on the path from the root has a region that holds pp, so line L1 and line L14 follow one path, and by part 2 the point is stored exactly when it is in the point page reached.

INSERT. Line L2 adds pp to the point page that holds it, so part 2 holds, and part 4 can fail only on the path. We claim that when the loop of lines L3 to L9 reaches uu on the path, (K) and (G) hold except for part 4 at uu, where uu has one entry or point too many. This is true for the point page. If uu is within capacity, line L4 stops with (K) and (G) everywhere. Otherwise line L5 chooses a cut that, by Lemma 2 or the point page argument, puts at most MM entries, or at most BB points, on each side; line L6 applies SPLIT, which by Lemma 1 gives two pages at the level of uu that satisfy (K) and (G) below them. If uu is the root, line L7 makes a new root with two children whose regions partition the plane along one line, which is guillotine; every point page gets one level deeper, so part 3 holds, and the loop stops. Otherwise line L8 replaces uu by ℓ\ell and rr in its parent. Their regions partition the region of uu, so part 1 and (G) hold at the parent, which now has one entry more, as in the claim. The loop goes up one level per pass, so it stops after at most h+1h + 1 passes, and then (K) holds.

DELETE. Lines L14 and L15 remove pp from the only page where it can be. This keeps parts 1 to 4, since part 4 has no lower bound for point pages.

RANGE-SEARCH. Each page is pushed once, by its parent, so the loop stops, and by part 2 no point is reported twice. Each reported point is in the box by the test of line L12. Let qq be stored and in the box, at the point page ww. Every page on the path from the root to ww has a region that holds qq, by part 1, so it meets the box, line L11 does not skip it, and line L13 pushes the next page of the path. So ww is visited, and line L12 reports qq. ■\blacksquare

Back to k-d-B tree