/// <summary>Continues cutting the tree in two, assuming that child nodes have been handled.</summary> private static void PartitionUpwardToParentSideOf(NestingDepthTreeNode n, int d, NestingDepthTreeNode orphan) { if (n == null) return; n.RecomputeAggregates(); var p = n._parent; if (n.DirToParent() == d) { // going from n to p crosses the cut line, so we must disconnect them n._parent = null; // the orphan node takes n's place p.SetChild(-d, orphan); if (orphan != null) orphan._parent = p; // switch directions back towards the cut, and onward with our new orphan n! PartitionUpwardToParentSideOf(p, -d, n); } else { // didn't pass over the cut line, keep going upwards PartitionUpwardToParentSideOf(p, d, orphan); } }
public static IncludeResult IncludeHelper(NestingDepthTreeNode root, int index, int adjust, int refAdjust) { // Do we need to create a new node? if (root == null) { return new IncludeResult(new NestingDepthTreeNode(index, adjust, refAdjust)); } // It is understood that the caller will fixup our parent afterwards; we must act independently of the tree above us root._parent = null; // Is this node the one we need to adjust? if (index == root._offset) { root._adjust += adjust; root._refCount += refAdjust; root.RecomputeAggregates(); // nodes can be removed when they are not referenced and have no effect on the totals if (root._adjust == 0 && root._refCount == 0) { return new IncludeResult(null, root.Implode()); } return new IncludeResult(root); } // Pick the subtree the node has to end up and recurse the inclusion that-a-way var d = index.CompareTo(root._offset); var subtree = root.Child(d); var preTotal = GetTotalAdjust(subtree); var subResult = IncludeHelper(subtree, index, adjust, refAdjust); var postTotal = GetTotalAdjust(subResult.NewRoot); if (preTotal + adjust != postTotal) { throw new InvalidOperationException("Invariant violated: total adjustment did not shift by the included adjustment."); } // Great! Now we just need to fixup so the new subtree is linked in var c = subResult.NewRoot; root.SetChild(d, c); if (c != null) c._parent = root; root.RecomputeAggregates(); // Oh, and do a token effort to keep things balanced using our hacky hierarchical ordering over the indexes // Can we get away with not rotating the new child above ourselves to keep things sorta balanced? if (c == null || !c.ShouldBeParentOf(root)) { return new IncludeResult(subResult.AdjustedNode, root); } // darn, need to rotate var s = c.Child(-d); c.SetChild(-d, root); root.SetChild(d, s); // fixup c._parent = null; root._parent = c; if (s != null) s._parent = root; root.RecomputeAggregates(); c.RecomputeAggregates(); // finally return new IncludeResult(subResult.AdjustedNode, c); }