Example #1
0
        private void RotateLL()
        {
            TTreeNode <TItem, TNode> left       = Left;
            TTreeNode <TItem, TNode> leftsRight = left.Right;

            if (Parent != null)
            {
                if (Parent.Left == this)
                {
                    Parent.Left = (TNode)left;
                }
                else
                {
                    Parent.Right = (TNode)left;
                }
            }

            left.Parent = Parent;
            left.Right  = (TNode)this;
            Parent      = (TNode)left;
            Left        = (TNode)leftsRight;

            if (leftsRight != null)
            {
                leftsRight.Parent = (TNode)this;
            }

            if (left.Parent == null)
            {
                Tree.RootNode = (TNode)left;
            }

            UpdateHeight(HeightUpdateType.UpdateAllUpwards);
        }
Example #2
0
        private void RotateRR()
        {
            TTreeNode <TItem, TNode> nodeRight      = Right;
            TTreeNode <TItem, TNode> nodeRightsLeft = nodeRight.Left;

            if (Parent != null)
            {
                if (Parent.Left == this)
                {
                    Parent.Left = (TNode)nodeRight;
                }
                else
                {
                    Parent.Right = (TNode)nodeRight;
                }
            }

            nodeRight.Parent = Parent;
            nodeRight.Left   = (TNode)this;
            Parent           = (TNode)nodeRight;
            Right            = (TNode)nodeRightsLeft;

            if (nodeRightsLeft != null)
            {
                nodeRightsLeft.Parent = (TNode)this;
            }

            if (nodeRight.Parent == null)
            {
                Tree.RootNode = (TNode)nodeRight;
            }

            UpdateHeight(HeightUpdateType.UpdateAllUpwards);
        }
Example #3
0
 public SearchResult(TItem value, TTreeNode <TItem, TNode> node, int index)
 {
     Value = value;
     Node  = node;
     Index = index;
 }
Example #4
0
        /// <summary>
        /// Adds the specified item.
        /// </summary>
        /// <param name="item">The item.</param>
        /// <returns>True if the item was added or false if it already existed and was not </returns>
        public bool AddItem(TItem item)
        {
            bool isBoundingNode;
            int  comparedToFirst = 0;

            //Is this the bounding node for the new item? If the node is empty it is considered to be the bounding node.
            if (ItemCount == 0)
            {
                isBoundingNode = true;
            }
            else
            {
                //Compare the item to be inserted to the first item in the data
                comparedToFirst = item.CompareTo(m_data[0]);
                isBoundingNode  = ((comparedToFirst >= 0) && (item.CompareTo(m_data[ItemCount - 1]) <= 0));
            }

            if (isBoundingNode)
            {
                //Is there space in this node?
                if (ItemCount < m_data.Length)
                {
                    //This is the bounding node, add the new item
                    return(InsertInCurrentNode(item, ShiftType.NoShift));
                }
                else
                {
                    //Copy the old minimum. This current item will be inserted into this node
                    TItem oldMinimum = m_data[0];

                    if (!InsertInCurrentNode(item, ShiftType.FullShiftToLeft))
                    {
                        return(false);
                    }

                    //Add the old minimum
                    if (Left == null)
                    {
                        //There is no left child, so create it
                        Left = CreateChild(oldMinimum);
                        UpdateHeight(HeightUpdateType.CurrentLevelOnly);
                        Rebalance(BalanceType.StopAfterFirstRotate);
                        return(true);
                    }
                    else
                    {
                        //Add the old minimum to the left child
                        return(Left.AddItem(oldMinimum));
                    }
                }
            }
            else
            {
                //If the item is less than the minimum and there is a left node, follow it
                if ((Left != null) && (comparedToFirst < 0))
                {
                    return(Left.AddItem(item));
                }

                //If the item is less than the maximum and there is a right node, follow it
                if ((Right != null) && (comparedToFirst > 0))
                {
                    return(Right.AddItem(item));
                }

                //If we are here then, there is no bounding node for this value.
                //Is there place in this node
                if (ItemCount < m_data.Length)
                {
                    //There is place in this node so add the new value. However since this value
                    // must be the new minimum or maximum (otherwise it would have found a bounding
                    // node) dont call InsertInCurrentNode which would do a binary search to find
                    // an insert location. Rather check for min/max and add it here.
                    if (comparedToFirst > 0)
                    {
                        //The item is greater than the minimum, therfore it must be the new maximum.
                        // Add it to the end of the array
                        m_data[ItemCount] = item;
                    }
                    else
                    {
                        //The item is the new miminum. Shift the array up and insert it.
                        Array.Copy(m_data, 0, m_data, 1, ItemCount);
                        m_data[0] = item;
                    }

                    ItemCount++;
                }
                else
                {
                    TTreeNode <TItem, TNode> newChild = CreateChild(item);

                    //Add it as the the left or the right child
                    if (comparedToFirst < 0)
                    {
                        Left = (TNode)newChild;
                    }
                    else
                    {
                        Right = (TNode)newChild;
                    }

                    UpdateHeight(HeightUpdateType.UpdateAllUpwards);
                    Rebalance(BalanceType.StopAfterFirstRotate);
                    return(true);
                }
            }

            return(true);
        }
Example #5
0
        public bool Remove(TItem item)
        {
            SearchResult <TItem, TNode> searchResult = SearchFor(item);

            if (searchResult == null)
            {
                return(false);
            }

            TTreeNode <TItem, TNode> rebalanceFrom = searchResult.Node;

            //If the remove will not cause an underflow then, delete the value and stop
            if (searchResult.Node.ItemCount > searchResult.Node.m_minimum)
            {
                DeleteFoundValue(searchResult);
                return(true);
            }

            if (searchResult.Node.IsInternal)
            {
                //Shift the array to the right "delete"
                // This is faster than calling DeleteFoundValue() because now there is no need to shift
                // the array a second time to make space for the greatest lower bound
                if (searchResult.Index > 0)
                {
                    Array.Copy(searchResult.Node.m_data, searchResult.Index - 1, searchResult.Node.m_data, searchResult.Index, searchResult.Node.m_data.Length - 1 - searchResult.Index);
                }

                //Insert the greatest lower bound
                m_data[0] = searchResult.Node.Left.CutGreatestLowerBound();
            }
            else              //This is a leaf or half-leaf so just delete the value (leaves and half-leaves are permitted to underflow)
            {
                DeleteFoundValue(searchResult);

                //If this is a half leaf and it can be merged with a leaf, then combine
                if (searchResult.Node.IsHalfLeaf)
                {
                    var child = searchResult.Node.Left ?? searchResult.Node.Right;

                    //If all the child items can fit into this node
                    if (searchResult.Node.ItemCount + child.ItemCount <= MaxItems)
                    {
                        //TODO consider not looping - the child is sorted, insert all the items at once, either at the begining or at the end (left/right)
                        for (int i = 0; i < child.ItemCount; ++i)
                        {
                            searchResult.Node.InsertInCurrentNode(child.m_data[i], ShiftType.NoShift);
                        }

                        //Remove the child
                        searchResult.Node.Left     = searchResult.Node.Right = null;
                        searchResult.Node.m_height = 0;
                    }
                }
                else                 //Is leaf
                {
                    if (searchResult.Node.ItemCount != 0)
                    {
                        //This is a non-empty leaf. Nothing more to do
                        return(true);
                    }
                    else
                    {
                        //The node is empty. So, unles this is the root, remove the node from its parent.
                        if (searchResult.Node.Parent != null)
                        {
                            if (searchResult.Node.Parent.Left == searchResult.Node)
                            {
                                searchResult.Node.Parent.Left = null;
                            }
                            else
                            {
                                searchResult.Node.Parent.Right = null;
                            }

                            //The current node has been deleted, so rebalance from its parent
                            rebalanceFrom = rebalanceFrom.Parent;
                        }
                    }
                }
            }

            rebalanceFrom.Rebalance(BalanceType.StopAfterEvenBalanceFound);
            return(true);
        }