private void FixTreeOnInsert(TextAnchorNode node)
{
Debug.Assert(node != null);
Debug.Assert(node.color == RED);
Debug.Assert(node.left == null || node.left.color == BLACK);
Debug.Assert(node.right == null || node.right.color == BLACK);
var parentNode = node.parent;
if (parentNode == null)
{
// we inserted in the root -> the node must be black
// since this is a root node, making the node black increments the number of black nodes
// on all paths by one, so it is still the same for all paths.
node.color = BLACK;
return;
}
if (parentNode.color == BLACK)
{
// if the parent node where we inserted was black, our red node is placed correctly.
// since we inserted a red node, the number of black nodes on each path is unchanged
// -> the tree is still balanced
return;
}
// parentNode is red, so there is a conflict here!
// because the root is black, parentNode is not the root -> there is a grandparent node
var grandparentNode = parentNode.parent;
var uncleNode = Sibling(parentNode);
if (uncleNode != null && uncleNode.color == RED)
{
parentNode.color = BLACK;
uncleNode.color = BLACK;
grandparentNode.color = RED;
FixTreeOnInsert(grandparentNode);
return;
}
// now we know: parent is red but uncle is black
// First rotation:
if (node == parentNode.right && parentNode == grandparentNode.left)
{
RotateLeft(parentNode);
node = node.left;
}
else if (node == parentNode.left && parentNode == grandparentNode.right)
{
RotateRight(parentNode);
node = node.right;
}
// because node might have changed, reassign variables:
parentNode = node.parent;
grandparentNode = parentNode.parent;
// Now recolor a bit:
parentNode.color = BLACK;
grandparentNode.color = RED;
// Second rotation:
if (node == parentNode.left && parentNode == grandparentNode.left)
{
RotateRight(grandparentNode);
}
else
{
// because of the first rotation, this is guaranteed:
Debug.Assert(node == parentNode.right && parentNode == grandparentNode.right);
RotateLeft(grandparentNode);
}
}