======================================================================
Remove
Remove shares some of the same mechanims used for insert and balancing.
Let's say we are removing the node with key 10.
100
/ \
/ \
/ \
/ \
50 130
/ \ \
/ \ \
/ \ \
/ \ \
/ \ \
/ \ \
10 80 150
/
/
/
70
We will assume 100 is the root for this example,
but this could also be an internal sub-tree.
Collect all nodes as stack from root to the node we are deleting.
e.g. [100, 50, 10]
Note: if you don't have a stack class handy, any list class will do.
child (to delete): 10
parent: 50
grandparent: 100
Zooming in on parent.removeChild(child)
50 50
/ \ \
/ \ \
/ \ \
/ \ \
/ \ \
/ \ \
10 80 80
/ /
/ /
/ /
70 70
Rebalance
50
\
\ 70
\ / \
\ / \
\ balance / \
\ ==============> / \
80 (right-left) 50 80
/
/
/
70
Reset grandparent's left with balanced node (70)
100
/ \
/ \
/ \
/ \
70 130
/ \ \
/ \ \
/ \ \
/ \ \
/ \ \
/ \ \
50 80 150
==============
Other Considerations
Resetting height
For cases where the sub-tree (like in the previous example)
has ancestor nodes above it in the tree, each ancestor
in the path from the root to the the
grandparent node (100) should recalculate height,
which is simply the max of its child heights.
Removing node with children
If removing a node that has child nodes,
we can use the similar rotation concepts,
but with the removal added in.
Say we are removing 10, we could rotate like this:
first rotate left to remove child (5) skew to right
10 10
/ \ / \
/ \ / \
/ \ / \
5 40 5 40
\ /
\ /
\ /
8 8
the new parent add old right (40)
(to replace 10) to new parent
5 5
/ / \
/ / \
/ / \
8 8 40