|
|
(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:
|