示例#1
0
 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();
 }
示例#2
0
 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);
             }
         }
     }
 }
示例#3
0
        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);
        }
示例#4
0
        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);
                    }
                }
            }
        }
示例#5
0
        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();
                }
            }
        }
示例#6
0
        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;
        }
示例#7
0
        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();
                }
            }
        }
示例#8
0
 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();
 }