public static void Add(ref DisjointSet left, Range right) { // An add is a normal binary tree insertion, // followed by a splay of the inserted node to the root. left = (left == null) ? right : Splay(left.Insert(right)); left.AssertWellOrdered(); }
private DisjointSet Find(ulong value) { checked { for (DisjointSet p = this, q; ; p = q) { p.AssertWellOrdered(); if (value < p.Value.Min) { q = p.Left; if (q == null) { return(p); } } else if (value > p.Value.Max) { q = p.Right; if (q == null) { return(p); } } else { return(p); } } } }
private static DisjointSet Splay(DisjointSet found) { for (DisjointSet grandparent; found.Parent != null;) { found.AssertWellOrdered(); grandparent = found.Parent.Parent; if (grandparent == null) { if (found.Parent.Right == found) { ZigFromRight(found.Parent); } else { ZigFromLeft(found.Parent); } } else if (grandparent.Right != null && grandparent.Right.Right == found) { ZigZigFromRight(grandparent); } else if (grandparent.Left != null && grandparent.Left.Left == found) { ZigZigFromLeft(grandparent); } else if (grandparent.Right != null && grandparent.Right.Left == found) { ZigZagFromRight(grandparent); } else if (grandparent.Left != null && grandparent.Left.Right == found) { ZigZagFromLeft(grandparent); } else { throw new ApplicationException("Splay tree parent/child relationships violated."); } } Debug.Assert(found.Parent == null); found.AssertWellOrdered(); return(found); }
private DisjointSet Insert(Range value) { checked { for (DisjointSet p = this, q; ; p = q) { // If the new range is strictly less than or greater than the // existing range and is not *adjacent*, descend down the left // or right subtree like a normal binary-tree search. If there // is no appropriate subtree, insert a brand new node. if (value.Max < p.Value.Min - (p.Value.Min > ulong.MinValue ? 1ul : 0ul)) { q = p.Left; if (q == null) { p.Left = new DisjointSet(null, value, null); p.Left.Parent = p; return(p.Left); } } else if (value.Min > p.Value.Max + (p.Value.Max < ulong.MaxValue ? 1ul : 0ul)) { q = p.Right; if (q == null) { p.Right = new DisjointSet(null, value, null); p.Right.Parent = p; return(p.Right); } } // But if the ranges overlap or are adjacent, we've found our mark. else { // Get the left and right subtrees. DisjointSet left = p.Left, right = p.Right; // Eliminate all subtrees that overlap or are adjacent to the new range. // Detach the subtrees so we can splay them. // Splay each subtree so the value for comparison will be at the top. // Each time, adjust the new range if the existing ranges extend the bounds. if (left != null) { do { DisjointSet parent = left.Parent; left.Parent = null; left = Splay(left.Find(value.Min)); left.Parent = Parent; if (value.Min <= left.Value.Max + (left.Value.Max < ulong.MaxValue ? 1ul : 0ul)) { value = new Range(Math.Min(value.Min, left.Value.Min), value.Max); left = left.Left; } else { break; } } while (left != null); } if (right != null) { do { DisjointSet parent = right.Parent; right.Parent = null; right = Splay(right.Find(value.Max)); right.Parent = parent; if (right.Value.Min - (right.Value.Min > ulong.MinValue ? 1ul : 0ul) <= value.Max) { value = new Range(value.Min, Math.Max(value.Max, right.Value.Max)); right = right.Right; } else { break; } } while (right != null); } // Now extend the bounds of the range at the root of the tree. p.Value = new Range(Math.Min(value.Min, p.Value.Min), Math.Max(value.Max, p.Value.Max)); // Reattach the eliminated subtrees' branches, which are now not adjacent to the new value. p.Left = left; p.Right = right; // Reattach their parents. if (left != null) { left.Parent = p; left.AssertWellOrdered(); } if (right != null) { right.Parent = p; right.AssertWellOrdered(); } // Return the "inserted" node. p.AssertWellOrdered(); return(p); } } } }
public static void Remove(ref DisjointSet left, Range right) { checked { // If the set is already empty, do nothing. if (left == null) { return; } // We must first ensure that the range we want to remove is present // in the set as a single, contiguous range. (This could be done // without this step but would be much more complicated.) Fortunately, // the Add operation already does this for us via Insert. // Add also splays the new range to the root of the tree. Add(ref left, right); Debug.Assert(left.Value.Min <= right.Min && left.Value.Max >= right.Max, "The Add operation did not leave the new range at the root."); // If the range at the root is now completely equal to the range to remove, // all we have to do is then delete it with a standard Splay Tree deletion. if (right == left.Value) { if (left.Left != null) { // First completely remove the existing root from the tree. if (left.Left != null) { left.Left.Parent = null; } if (left.Right != null) { left.Right.Parent = null; } // Then find the root's predecessor, which will have no right subtree. DisjointSet pred = Splay(left.Left.FindMax()); Debug.Assert(pred.Right == null); Debug.Assert(pred.Parent == null); // Then attach the old right subtree. pred.Right = left.Right; if (pred.Right != null) { pred.Right.Parent = pred; } // Finally, "return" the new root. left = pred; } else { // If there is no predecessor, the right subtree (if any) becomes the root, // and the old root is thrown away completely. left = left.Right; if (left != null) { left.Parent = null; } } } // Otherwise, the range to remove is a subset of the existing contiguous range, // which we have to split depending on which portion is affected. else if (left.Value.Min == right.Min) { // If one of the endpoints of the range to remove is the same as the root // range, all we have to do is adjust the range. Debug.Assert(right.Max < left.Value.Max); left.Value = new Range(right.Max + 1, left.Value.Max); } else if (left.Value.Max == right.Max) { // This is the same case but for the other endpoint. Debug.Assert(left.Value.Min < right.Min); left.Value = new Range(left.Value.Min, right.Min - 1); } else { // If neither endpoint is equal, we have to make a "hole" in the middle, // which creates an additional node in the tree. Debug.Assert(left.Value.Max > right.Max); Debug.Assert(left.Value.Min < right.Min); Range existing = left.Value; // The new node will be the existing node's successor, so we can insert // it manually as the new right subtree of the existing node. left.Value = new Range(existing.Min, right.Min - 1); left.Right = new DisjointSet(null, new Range(right.Max + 1, existing.Max), left.Right); left.Right.Parent = left; if (left.Right.Right != null) { left.Right.Right.Parent = left.Right; } // Finally, splay the new node to the root and "return" it. left = Splay(left.Right); } if (left != null) { Debug.Assert(left.Parent == null); left.AssertWellOrdered(); } } }
private static DisjointSet Splay(DisjointSet found) { for(DisjointSet grandparent; found.Parent != null; ) { found.AssertWellOrdered(); grandparent = found.Parent.Parent; if(grandparent == null) if(found.Parent.Right == found) ZigFromRight(found.Parent); else ZigFromLeft(found.Parent); else if(grandparent.Right != null && grandparent.Right.Right == found) ZigZigFromRight(grandparent); else if(grandparent.Left != null && grandparent.Left.Left == found) ZigZigFromLeft(grandparent); else if(grandparent.Right != null && grandparent.Right.Left == found) ZigZagFromRight(grandparent); else if(grandparent.Left != null && grandparent.Left.Right == found) ZigZagFromLeft(grandparent); else throw new ApplicationException("Splay tree parent/child relationships violated."); } Debug.Assert(found.Parent == null); found.AssertWellOrdered(); return found; }
public static void Remove(ref DisjointSet left, Range right) { checked { // If the set is already empty, do nothing. if(left == null) return; // We must first ensure that the range we want to remove is present // in the set as a single, contiguous range. (This could be done // without this step but would be much more complicated.) Fortunately, // the Add operation already does this for us via Insert. // Add also splays the new range to the root of the tree. Add(ref left, right); Debug.Assert(left.Value.Min <= right.Min && left.Value.Max >= right.Max, "The Add operation did not leave the new range at the root."); // If the range at the root is now completely equal to the range to remove, // all we have to do is then delete it with a standard Splay Tree deletion. if(right == left.Value) { if(left.Left != null) { // First completely remove the existing root from the tree. if(left.Left != null) left.Left.Parent = null; if(left.Right != null) left.Right.Parent = null; // Then find the root's predecessor, which will have no right subtree. DisjointSet pred = Splay(left.Left.FindMax()); Debug.Assert(pred.Right == null); Debug.Assert(pred.Parent == null); // Then attach the old right subtree. pred.Right = left.Right; if(pred.Right != null) pred.Right.Parent = pred; // Finally, "return" the new root. left = pred; } else { // If there is no predecessor, the right subtree (if any) becomes the root, // and the old root is thrown away completely. left = left.Right; if(left != null) left.Parent = null; } } // Otherwise, the range to remove is a subset of the existing contiguous range, // which we have to split depending on which portion is affected. else if(left.Value.Min == right.Min) { // If one of the endpoints of the range to remove is the same as the root // range, all we have to do is adjust the range. Debug.Assert(right.Max < left.Value.Max); left.Value = new Range(right.Max + 1, left.Value.Max); } else if(left.Value.Max == right.Max) { // This is the same case but for the other endpoint. Debug.Assert(left.Value.Min < right.Min); left.Value = new Range(left.Value.Min, right.Min - 1); } else { // If neither endpoint is equal, we have to make a "hole" in the middle, // which creates an additional node in the tree. Debug.Assert(left.Value.Max > right.Max); Debug.Assert(left.Value.Min < right.Min); Range existing = left.Value; // The new node will be the existing node's successor, so we can insert // it manually as the new right subtree of the existing node. left.Value = new Range(existing.Min, right.Min - 1); left.Right = new DisjointSet(null, new Range(right.Max + 1, existing.Max), left.Right); left.Right.Parent = left; if(left.Right.Right != null) left.Right.Right.Parent = left.Right; // Finally, splay the new node to the root and "return" it. left = Splay(left.Right); } if(left != null) { Debug.Assert(left.Parent == null); left.AssertWellOrdered(); } } }