|
|
|
|
|
(The resulting tree is no longer an AVL tree !!)
|
|
|
This "node re-arrangement" operation is called tri-node reconstruction operation (by Goodrich).
(BTW, the classic way to do re-balancing is with a bunch of "left-rotation", "right-rotation", "right-left-rotation", "right-right-rotation", etc..)
|
|
|
To preserve the property of a Binary Search Tree (left subtree with smaller keys and right subtree with larger keys), we must attach the subtrees T0, T1, T2 and T3 to the nodes x, y and z as follows:
|
This is the first tri-node reconstruction operation:
|
|
|
|
|
Procedure summary:
|
|
|
|
Conclusion:
|
|
Graphically:
|
|
The configurations can be characterized as follows:
|
Remember that:
|
|
|
|
I have spare you the discovery.... here are the 4 different tri-node reconstruction operations
|
|
Let x = first imbalanced node
Let y = child node of imbalance node x (on the way to the inserted node)
Let z = grand child of imbalance node x (on the way to the inserted node)
(1) Identify the configuration;
which node is a ?
which node is b ?
which node is c ?
where is subtree T0 (= root of subtree T0) ?
where is subtree T1 (= root of subtree T1) ?
where is subtree T2 (= root of subtree T2) ?
where is subtree T3 (= root of subtree T3) ?
(2) Make the links according to the tri-node reconstruction operation
(build from the top first)
(2.a) Make b the root of the new subtree
x's parent must now point to b !
(Be careful: if x is the root node, b will become the new root !)
(2.b) Now make these links:
b
/ \ Note: don't forget the PARENT links !!!
a c
(2.c) Then these links:
b
/ \
a c
/ \
T0 T1
(2.d) And finally these links:
b
/ \
a c
/ \
T2 T3
Recompute the heights of a, c, b and all nodes from b to root.
Done.
|
(Goodrich's code is Chinese to me... took me a while to figure out what he was trying to do, ain't not way in hell I'm using it to teach.....)
/* =======================================================
tri_node_restructure(x, y, z):
x = parent(y)
y = parent(z)
======================================================= */
public void tri_node_restructure( BSTEntry x, BSTEntry y, BSTEntry z)
{
/* *******************************************************************
Determine the parent child relationships between (y,z) and (x,y))
******************************************************************* */
/* =======================================================
Determine the node configuration:
find out which nodes are in positions a, b and c
given in the following legend:
b
/ \
a c
/ \ / \
T0 T1 T2 T3
======================================================= */
BSTEntry a, b, c;
BSTEntry T0, T1, T2, T3;
boolean zIsLeftChild = (z == y.left);
boolean yIsLeftChild = (y == x.left);
if (zIsLeftChild && yIsLeftChild)
{ /* Configuration 1 */
a = z; // x=c
b = y; // / \
c = x; // y=b T3
T0 = a.left; // / \
T1 = a.right; // z=a T2
T2 = b.right; // / \
T3 = c.right; // T0 T1
}
else if (!zIsLeftChild && yIsLeftChild)
{ /* Configuration 2 */
a = y; // x=c
b = z; // / \
c = x; // y=a T3
T0 = a.left; // / \
T1 = b.left; // T0 z=b
T2 = b.right; // / \
T3 = c.right; // T1 T2
}
else if (zIsLeftChild && !yIsLeftChild)
{ /* Configuration 4 */
a = x; // x=a
b = z; // / \
c = y; // T0 y=c
T0 = a.left; // / \
T1 = b.left; // z=b T3
T2 = b.right; // / \
T3 = c.right; // T1 T2
}
else
{ /* Configuration 3 */
a = x; // x=a
b = y; // / \
c = z; // T0 y=b
T0 = a.left; // / \
T1 = b.left; // T1 z=c
T2 = c.left; // / \
T3 = c.right; // T2 T3
}
/* ------------------------------------------------------------------
Old Tree: New tree:
x's parent x's parent
| |
x b
Put b at x's place
------------------------------------------------------------------ */
if ( x == root )
{ /* If x is the root node, handle the replacement differently.... */
root = b; // Need to update root !
b.parent = null;
}
else
{
BSTEntry xParent;
xParent = x.parent; // Find x's parent
if ( x == xParent.left )
{ /* Link b to the left branch of x's parent */
b.parent = xParent;
xParent.left = b;
}
else
{ /* Link b to the right branch of x's parent */
b.parent = xParent;
xParent.right = b;
}
}
/* ======================================================
Now we can make the REST of the tree (from b down)
b
/ \
a c
/ \ / \
T0 T1 T2 T3
======================================================= */
/* ------------------
Make: b
/ \
a c
------------------ */
b.left = a;
a.parent = b;
b.right = c;
c.parent = b;
/* ------------------
Make: b
/ \
a c
/ \
T0 T1
------------------ */
a.left = T0;
if ( T0 != null ) T0.parent = a;
a.right = T1;
if ( T1 != null ) T1.parent = a;
/* ------------------
Make: b
/ \
a c
/ \
T2 T3
------------------ */
c.left = T2;
if ( T2 != null ) T2.parent= c;
c.right= T3;
if ( T3 != null ) T3.parent= c;
/* ======================================
Recompute the heights of the nodes
====================================== */
recompHeight(a);
recompHeight(c);
}
|
public void put(String k, Integer v)
{
insert (k,v) using the ordinary BST put(k,v) algorithm;
(I leave the code out for brevity)
/* --------------------------------------------
Recompute the height of all parent nodes...
-------------------------------------------- */
recompHeight(p);
/* --------------------------------------------------------
Check for height violation starting at insert location
-------------------------------------------------------- */
BSTEntry x, y, z;
x = y = z = q; // Start search at q (new node)
while ( x != null ) // Traverse all the way up to the root node....
{
if ( diffHeight(x.left, x.right) <= 1 )
{
/* =============================================
No violation --> continue to the next level
============================================= */
z = y; // Go up the tree one level
y = x;
x = x.parent;
}
else
{
break; // Found the first violation
}
}
if ( x != null )
{
tri_node_restructure( x, y, z ); // Re-balance the AVL tree
}
}
|
How to run the program:
|