private void ReplaceNode(HeightTreeNode replacedNode, HeightTreeNode newNode) { if (replacedNode.parent == null) { Debug.Assert(replacedNode == root); root = newNode; } else { if (replacedNode.parent.left == replacedNode) { replacedNode.parent.left = newNode; } else { replacedNode.parent.right = newNode; } } if (newNode != null) { newNode.parent = replacedNode.parent; } replacedNode.parent = null; }
private void FixTreeOnInsert(HeightTreeNode 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); HeightTreeNode 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 HeightTreeNode grandparentNode = parentNode.parent; HeightTreeNode 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); } }
private void BeforeNodeReplace(HeightTreeNode removedNode, HeightTreeNode newNode, HeightTreeNode newNodeOldParent) { Debug.Assert(removedNode != null); Debug.Assert(newNode != null); while (newNodeOldParent != removedNode) { if (newNodeOldParent.collapsedSections != null) { foreach (CollapsedLineSection cs in newNodeOldParent.collapsedSections) { newNode.lineNode.AddDirectlyCollapsed(cs); } } newNodeOldParent = newNodeOldParent.parent; } if (newNode.collapsedSections != null) { foreach (CollapsedLineSection cs in newNode.collapsedSections) { newNode.lineNode.AddDirectlyCollapsed(cs); } } newNode.collapsedSections = removedNode.collapsedSections; MergeCollapsedSectionsIfPossible(newNode); }
private static void UpdateAfterChildrenChange(HeightTreeNode node) { UpdateAugmentedData(node, UpdateAfterChildrenChangeRecursionMode.IfRequired); }
private static void AddRemoveCollapsedSectionDown(CollapsedLineSection section, HeightTreeNode node, int sectionLength, bool add) { while (true) { if (node.left != null) { if (node.left.totalCount < sectionLength) { // mark left subtree if (add) { node.left.AddDirectlyCollapsed(section); } else { node.left.RemoveDirectlyCollapsed(section); } sectionLength -= node.left.totalCount; } else { // mark only inside the left subtree node = node.left; Debug.Assert(node != null); continue; } } if (add) { node.lineNode.AddDirectlyCollapsed(section); } else { node.lineNode.RemoveDirectlyCollapsed(section); } sectionLength -= 1; if (sectionLength == 0) { // done! Debug.Assert(node.documentLine == section.End); break; } // mark inside right subtree: node = node.right; Debug.Assert(node != null); } }
private void AddRemoveCollapsedSection(CollapsedLineSection section, int sectionLength, bool add) { Debug.Assert(sectionLength > 0); HeightTreeNode node = GetNode(section.Start); // Go up in the tree. while (true) { // Mark all middle nodes as collapsed if (add) { node.lineNode.AddDirectlyCollapsed(section); } else { node.lineNode.RemoveDirectlyCollapsed(section); } sectionLength -= 1; if (sectionLength == 0) { // we are done! Debug.Assert(node.documentLine == section.End); break; } // Mark all right subtrees as collapsed. if (node.right != null) { if (node.right.totalCount < sectionLength) { if (add) { node.right.AddDirectlyCollapsed(section); } else { node.right.RemoveDirectlyCollapsed(section); } sectionLength -= node.right.totalCount; } else { // mark partially into the right subtree: go down the right subtree. AddRemoveCollapsedSectionDown(section, node.right, sectionLength, add); break; } } // go up to the next node HeightTreeNode parentNode = node.parent; Debug.Assert(parentNode != null); while (parentNode.right == node) { node = parentNode; parentNode = node.parent; Debug.Assert(parentNode != null); } node = parentNode; } UpdateAugmentedData(GetNode(section.Start), UpdateAfterChildrenChangeRecursionMode.WholeBranch); UpdateAugmentedData(GetNode(section.End), UpdateAfterChildrenChangeRecursionMode.WholeBranch); }
private static bool GetColor(HeightTreeNode node) { return(node != null ? node.color : BLACK); }
private void FixTreeOnDelete(HeightTreeNode node, HeightTreeNode parentNode) { Debug.Assert(node == null || node.parent == parentNode); if (parentNode == null) { return; } // warning: node may be null HeightTreeNode sibling = Sibling(node, parentNode); if (sibling.color == RED) { parentNode.color = RED; sibling.color = BLACK; if (node == parentNode.left) { RotateLeft(parentNode); } else { RotateRight(parentNode); } sibling = Sibling(node, parentNode); // update value of sibling after rotation } if (parentNode.color == BLACK && sibling.color == BLACK && GetColor(sibling.left) == BLACK && GetColor(sibling.right) == BLACK) { sibling.color = RED; FixTreeOnDelete(parentNode, parentNode.parent); return; } if (parentNode.color == RED && sibling.color == BLACK && GetColor(sibling.left) == BLACK && GetColor(sibling.right) == BLACK) { sibling.color = RED; parentNode.color = BLACK; return; } if (node == parentNode.left && sibling.color == BLACK && GetColor(sibling.left) == RED && GetColor(sibling.right) == BLACK) { sibling.color = RED; sibling.left.color = BLACK; RotateRight(sibling); } else if (node == parentNode.right && sibling.color == BLACK && GetColor(sibling.right) == RED && GetColor(sibling.left) == BLACK) { sibling.color = RED; sibling.right.color = BLACK; RotateLeft(sibling); } sibling = Sibling(node, parentNode); // update value of sibling after rotation sibling.color = parentNode.color; parentNode.color = BLACK; if (node == parentNode.left) { if (sibling.right != null) { Debug.Assert(sibling.right.color == RED); sibling.right.color = BLACK; } RotateLeft(parentNode); } else { if (sibling.left != null) { Debug.Assert(sibling.left.color == RED); sibling.left.color = BLACK; } RotateRight(parentNode); } }