When we delete a node from a threaded tree, we have to update one or two
more pointers than if it were an unthreaded BST. What's more, we
sometimes have to go to a bit of effort to track down what pointers
these are, because they are in the predecessor and successor of the node
being deleted.

We search down the tree to find the item to delete, p. As we do it we
keep track of its parent q and the direction dir that we descended
from it. The initial value of q and dir use the trick seen
originally in copying a BST (see Copying a BST Iteratively).

There are nicer ways to do the same thing, though they are not
necessarily as efficient. See the exercises for one possibility.

The cases for deletion from a threaded tree are a bit different from
those for an unthreaded tree. The key point to keep in mind is that a
node with n children has n threads pointing to it that must be
updated when it is deleted. Let's look at the cases in detail now.

Case 1: p has a right thread and a left child

If p has a right thread and a left child, then we replace it by its
left child. We also replace its predecessor t's right thread by
p's right thread. In the most general subcase, the whole operation
looks something like this:

On the other hand, it can be as simple as this:

Both of these subcases, and subcases in between them in complication,
are handled by the same code:

Case 2: p has a right thread and a left thread

If p is a leaf, then no threads point to it, but we must change its
parent q's pointer to p to a thread, pointing to the same place that
the corresponding thread of p pointed. This is easy, and typically
looks something like this:

There is one special case, which comes up when q is the pseudo-node
used for the parent of the root. We can't access tbst_tag[] in this
“node”. Here's the code:

Case 4: p's right child has a left child

If p has a right child, which in turn has a left child, we arrive at
the most complicated case. It corresponds to case 3 in deletion from
an unthreaded BST. The solution is to find p's successor s and
move it in place of p. In this case, r is s's parent node, not
necessarily p's right child.

There are two subcases here. In the first, s has a right child. In
that subcase, s's own successor's left thread already points to s,
so we need not adjust any threads. Here's an example of this subcase.
Notice how the left thread of node 3, s's successor, already points
to s.

The second subcase comes up when s has a right thread. Because s
also has a left thread, this means that s is a leaf. This subcase
requires us to change r's left link to a thread to its predecessor,
which is now s. Here's a continuation of the previous example,
showing deletion of the new root, node 2:

2. In case 2, we must handle q as the pseudo-root as a special case. Can
we rearrange the TBST data structures to avoid this?
[answer]

3. Rewrite case 4 to replace the deleted node's tbst_data by its
successor and actually delete the successor, instead of moving around
pointers. (Refer back to Exercise 4.8-3 for an explanation of why
this approach cannot be used in libavl.)
[answer]

*4. Many of the cases in deletion from a TBST require searching down the
tree for the nodes with threads to the deleted node. Show that this
adds only a constant number of operations to the deletion of a randomly
selected node, compared to a similar deletion in an unthreaded tree.
[answer]