Algorithm Search⌘K

Proofs: Threaded binary tree

These are the human proofs of Threaded binary tree, at full length.

Successor and insert are correct in a threaded binary search tree full

This proof shows: correctness.

We use the invariant of the page: (H1) the child links form a binary search tree with distinct keys, and (H2) each left thread points to the in-order predecessor and each right thread to the in-order successor (NIL at the two ends). Let x1,…,xnx_1, \ldots, x_n be the in-order sequence of the tree of child links, so x1.key<⋯<xn.keyx_1.key < \cdots < x_n.key by (H1).

Lemma 1. A node has a left child exactly when its left tag is false, and a right child exactly when its right tag is false. This is the meaning of the tags.

Lemma 2 (successor in a binary tree). In a binary tree, if xx has a right child, the in-order successor of xx is the leftmost node of the right subtree of xx. If xx has no right child, the successor is the lowest ancestor of xx whose left subtree contains xx, or nothing.

Proof. In-order visits the left subtree of a node, then the node, then its right subtree. If xx has a right subtree RR, the next node visited after xx is the first node of RR in in-order, which is the leftmost node of RR. If not, the subtree of xx is finished when xx is visited, and in-order returns up the ancestors; it visits next the first ancestor uu reached from its left subtree. □\square

Claim 1. SUCCESSOR(x)(x) returns xi+1x_{i+1} for x=xix = x_i, or NIL for i=ni = n.

Proof. If x.rthreadx.rthread is true, then xx has no right child (Lemma 1), and by (H2) x.rightx.right is xi+1x_{i+1} or NIL for i=ni = n; line L1 returns it. Else xx has a right child yy (line L2). The loop of line L3 moves from yy to its left child while the left tag is false, that is while a left child exists (Lemma 1), so it stops at the leftmost node of the subtree of yy, after at most hh steps because the depth grows by 1 in each step. By Lemma 2 this node is xi+1x_{i+1}. □\square

Corollary (walk). Starting at x1x_1 and applying SUCCESSOR until NIL visits x1,…,xnx_1, \ldots, x_n in order. Each left child link (u,u.left)(u, u.left) lies on exactly one maximal chain of left links; let tt be the top node of that chain. The chain is walked down once: by the first walk to the minimum if tt is the root, and else by line L3 in the call for the node whose right child is tt. Each right child link is followed once by line L2, in the call for its upper end, and each right thread once by line L1. So the walk takes O(n)O(n) steps.

Claim 2. If the tree satisfies (H1) and (H2) and kk is not a key, then after INSERT(T,k)(T, k) the tree satisfies (H1) and (H2) and its keys are the old keys and kk. If kk is a key, nothing changes.

Proof. If the tree is empty, line L5 makes a single node with two NIL threads, which satisfies both conditions. Else lines L6 to L12 follow the search path for kk in the tree of child links, because by Lemma 1 a move is made exactly when the child exists. If kk is found, line L8 returns without a change. Else the walk ends at a node xx whose field on the side of kk is a thread, which by Lemma 1 is an empty child position, the same position where BST insertion puts kk. The new node zz becomes the child of xx there, as a leaf, so (H1) holds by the correctness of BST insertion.

For (H2), assume k<x.keyk < x.key, so line L11 runs (the other case is the mirror image). Let x=xjx = x_j. Because xx had no left child, by Lemma 2 applied to predecessors its predecessor xj−1x_{j-1} is the old target of x.leftx.left (by (H2)), or none for j=1j = 1. In the new tree, zz is a leaf and is the whole left subtree of xx, so in-order visits zz right before xx. The nodes visited before zz are the nodes visited before xx in the old tree, in the same order, because no other subtree changed. The new sequence is x1,…,xj−1,z,xj,…,xnx_1, \ldots, x_{j-1}, z, x_j, \ldots, x_n.

Now check each thread. zz has both tags true, with z.leftz.left equal to the old x.leftx.left, which is xj−1x_{j-1} or NIL, its new predecessor, and z.right=x=xjz.right = x = x_j, its new successor. The node xx loses its left thread and gets the child zz, with its tag set to false. Each other node keeps its fields. Its in-order neighbours did not change, except for xj−1x_{j-1}, whose successor is now zz; but xj−1x_{j-1} has a right child or a right thread to xjx_j. In the second case xj−1x_{j-1} would have no right child, so its successor would be the lowest ancestor with xj−1x_{j-1} in its left subtree, which is xjx_j, and then xjx_j would have a left child in the old tree, which is false because the left field of xjx_j was a thread. So xj−1x_{j-1} has a right child, and its right field is not a thread. Hence every thread is correct, and (H2) holds. ■\blacksquare

Back to Threaded binary tree