void RemoveNode(HeightTreeNode removedNode) { if (removedNode.left != null && removedNode.right != null) { // replace removedNode with it's in-order successor HeightTreeNode leftMost = removedNode.right.LeftMost; HeightTreeNode parentOfLeftMost = leftMost.parent; RemoveNode(leftMost); // remove leftMost from its current location BeforeNodeReplace(removedNode, leftMost, parentOfLeftMost); // and overwrite the removedNode with it ReplaceNode(removedNode, leftMost); leftMost.left = removedNode.left; if (leftMost.left != null) leftMost.left.parent = leftMost; leftMost.right = removedNode.right; if (leftMost.right != null) leftMost.right.parent = leftMost; leftMost.color = removedNode.color; UpdateAfterChildrenChange(leftMost); if (leftMost.parent != null) UpdateAfterChildrenChange(leftMost.parent); return; } // now either removedNode.left or removedNode.right is null // get the remaining child HeightTreeNode parentNode = removedNode.parent; HeightTreeNode childNode = removedNode.left ?? removedNode.right; BeforeNodeRemove(removedNode); ReplaceNode(removedNode, childNode); if (parentNode != null) UpdateAfterChildrenChange(parentNode); if (removedNode.color == BLACK) { if (childNode != null && childNode.color == RED) { childNode.color = BLACK; } else { FixTreeOnDelete(childNode, parentNode); } } }
void MergeCollapsedSectionsIfPossible(HeightTreeNode node) { Debug.Assert(node != null); if (inRemoval) { nodesToCheckForMerging.Add(node); return; } // now check if we need to merge collapsedSections together bool merged = false; var collapsedL = node.lineNode.collapsedSections; if (collapsedL != null) { for (int i = collapsedL.Count - 1; i >= 0; i--) { CollapsedLineSection cs = collapsedL[i]; if (cs.Start == node.documentLine || cs.End == node.documentLine) continue; if (node.left == null || (node.left.collapsedSections != null && node.left.collapsedSections.Contains(cs))) { if (node.right == null || (node.right.collapsedSections != null && node.right.collapsedSections.Contains(cs))) { // all children of node contain cs: -> merge! if (node.left != null) node.left.RemoveDirectlyCollapsed(cs); if (node.right != null) node.right.RemoveDirectlyCollapsed(cs); collapsedL.RemoveAt(i); node.AddDirectlyCollapsed(cs); merged = true; } } } if (collapsedL.Count == 0) node.lineNode.collapsedSections = null; } if (merged && node.parent != null) { MergeCollapsedSectionsIfPossible(node.parent); } }
static void UpdateAugmentedData(HeightTreeNode node, UpdateAfterChildrenChangeRecursionMode mode) { int totalCount = 1; double totalHeight = node.lineNode.TotalHeight; if (node.left != null) { totalCount += node.left.totalCount; totalHeight += node.left.totalHeight; } if (node.right != null) { totalCount += node.right.totalCount; totalHeight += node.right.totalHeight; } if (node.IsDirectlyCollapsed) totalHeight = 0; if (totalCount != node.totalCount || !totalHeight.IsClose(node.totalHeight) || mode == UpdateAfterChildrenChangeRecursionMode.WholeBranch) { node.totalCount = totalCount; node.totalHeight = totalHeight; if (node.parent != null && mode != UpdateAfterChildrenChangeRecursionMode.None) UpdateAugmentedData(node.parent, mode); } }
static bool GetColor(HeightTreeNode node) { return node != null ? node.color : BLACK; }
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); } }
static void UpdateAfterChildrenChange(HeightTreeNode node) { UpdateAugmentedData(node, UpdateAfterChildrenChangeRecursionMode.IfRequired); }