示例#1
0
        HeightTreeNode GetNodeByVisualPosition(double position)
        {
            if (position <= 0)
            {
                return(root.LeftMost);
            }
            if (position > root.totalHeight)
            {
                return(root.RightMost);
            }
            HeightTreeNode node = root;

            while (true)
            {
                if (node.left != null && position < node.left.totalHeight)
                {
                    node = node.left;
                }
                else
                {
                    if (node.left != null)
                    {
                        position -= node.left.totalHeight;
                    }
                    position -= node.lineNode.TotalHeight;
                    if (position < 0 || node.right == null)
                    {
                        return(node);
                    }
                    // node.right==null can happen when totalHeight is incorrect due to rounding errors,
                    // so position can be below the rounded totalHeight but larger than the sum
                    // of all nodes
                    node = node.right;
                }
            }
        }
示例#2
0
 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;
 }
示例#3
0
        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);
            }
        }
示例#4
0
 static void UpdateAfterChildrenChange(HeightTreeNode node)
 {
     UpdateAugmentedData(node, UpdateAfterChildrenChangeRecursionMode.IfRequired);
 }
示例#5
0
        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);
        }
示例#6
0
 static bool GetColor(HeightTreeNode node)
 {
     return(node != null ? node.color : BLACK);
 }
示例#7
0
        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);
            }
        }