Esempio n. 1
0
            public TwoFourTreeNode Split()
            {
                Debug.Assert(IsKeyFull);

                var node = new TwoFourTreeNode(IsLeafNode)
                {
                    _items  = { [0] = _items[MaxKeyNum - 1] },
                    _keyNum = 1,
                    Parent  = Parent
                };

#if DEBUG
                Array.Clear(_items, 1, MaxKeyNum - 1);
#endif

                if (!IsLeafNode)
                {
                    Array.Copy(_children, MaxKeyNum - 1, node._children, 0, 2);
                    for (var i = 0; i <= node._keyNum; i++)
                    {
                        node._children[i].Parent = node;
                    }
#if DEBUG
                    Array.Clear(_children, MaxKeyNum - 1, 2);
#endif
                }

                _keyNum = 1;
                return(node);
            }
Esempio n. 2
0
 public void Clear()
 {
     _root.Clear();
     _root  = new TwoFourTreeNode(true);
     _count = 0;
     _version++;
 }
Esempio n. 3
0
 public TwoFourTreeNode(KeyValuePair <TKey, TValue> item, TwoFourTreeNode child1, TwoFourTreeNode child2) : this(false)
 {
     _items[0]     = item;
     _children[0]  = child1;
     _children[1]  = child2;
     child1.Parent = this;
     child2.Parent = this;
     _keyNum       = 1;
 }
Esempio n. 4
0
 public void PushFrontItemChild(KeyValuePair <TKey, TValue> item, TwoFourTreeNode node = null)
 {
     Debug.Assert(!IsKeyFull);
     Debug.Assert(node != null && !IsLeafNode || node == null && IsLeafNode);
     if (_keyNum > 0)
     {
         Array.Copy(_items, 0, _items, 1, _keyNum);
     }
     _items[0] = item;
     if (node != null)
     {
         Array.Copy(_children, 0, _children, 1, _keyNum + 1);
         _children[0] = node;
         node.Parent  = this;
     }
     _keyNum++;
 }
Esempio n. 5
0
            public void MergeWithRight(int rightIndex, TwoFourTreeNode right)
            {
                Debug.Assert(_keyNum == 0 && right._keyNum == 1 ||
                             _keyNum == 1 && right._keyNum == 0);
                Debug.Assert(Parent != null);
                Debug.Assert(Parent == right.Parent);
                Debug.Assert(Parent.Children[rightIndex] == right);

                var pair = Parent.RemoveItemChild(rightIndex - 1);

                AppendItemChild(pair.Item, IsLeafNode ? null : right._children[0]);

                if (right._keyNum != 0)
                {
                    AppendItemChild(right._items[0], IsLeafNode ? null : right._children[1]);
                }

                right.Invalidate();
            }
Esempio n. 6
0
        private void RemoveItem(TwoFourTreeNode node, int index)
        {
            /*
             * To remove a value from the 2–3–4 tree:
             *  1.	Find the element to be deleted.
             *      •	If the element is not in a leaf node, remember its location and continue searching until a leaf, which will contain the element’s successor, is reached.
             *          The successor can be either the largest key that is smaller than the one to be removed, or the smallest key that is larger than the one to be removed.
             *          It is simplest to make adjustments to the tree from the top down such that the leaf node found is not a 2-node. That way, after the swap, there will not be an empty leaf node.
             *      •	If the element is in a 2-node leaf, just make the adjustments below.
             *  Make the following adjustments when a 2-node – except the root node – is encountered on the way to the leaf we want to remove:
             *  1.	If a sibling on either side of this node is a 3-node or a 4-node (thus having more than 1 key), perform a rotation with that sibling:
             *      •	The key from the other sibling closest to this node moves up to the parent key that overlooks the two nodes.
             *      •	The parent key moves down to this node to form a 3-node.
             *      •	The child that was originally with the rotated sibling key is now this node's additional child.
             *  2.	If the parent is a 2-node and the sibling is also a 2-node, combine all three elements to form a new 4-node and shorten the tree. (This rule can only trigger if the parent 2-node is the root,
             *      since all other 2-nodes along the way will have been modified to not be 2-nodes. This is why "shorten the tree" here preserves balance; this is also an important assumption for the fusion operation.)
             *  3.	If the parent is a 3-node or a 4-node and all adjacent siblings are 2-nodes, do a fusion operation with the parent and an adjacent sibling:
             *      •	The adjacent sibling and the parent key overlooking the two sibling nodes come together to form a 4-node.
             *      •	Transfer the sibling's children to this node.
             *  Once the sought value is reached, it can now be placed at the removed entry's location without a problem because we have ensured that the leaf node has more than 1 key.
             */

            if (node.IsLeafNode)
            {
                node.RemoveItem(index);
                if (node.KeyNum == 0 && node != _root)
                {
                    Debug.Assert(node.Parent != null);
                    AdjustNodeWhenRemove(node);
                    // if (node.GetChildIndex() < 0) node.Invalidate();
                }
                _count--;
                _version++;
            }
            else
            {
                var successor = node.Children[index].GetMaxLeafNode();
                var item      = successor.Items[successor.KeyNum - 1];
                node.Items[index] = item;
                RemoveItem(successor, successor.KeyNum - 1);
            }
        }
Esempio n. 7
0
        private void Split(TwoFourTreeNode node)
        {
            var parent = node.Parent;

            Debug.Assert(node.IsKeyFull);
            var midKey  = node.Items[1];
            var newNode = node.Split();

            if (node == _root)
            {
                Debug.Assert(parent == null);
                var newRoot = new TwoFourTreeNode(midKey, node, newNode);
                _root = newRoot;
            }
            else
            {
                Debug.Assert(parent != null);
                var nodeIndex = node.GetChildIndex();
                Debug.Assert(parent.Children[nodeIndex] == node);
                parent.InsertItemChild(nodeIndex, midKey, newNode);
            }
        }
Esempio n. 8
0
            public void InsertItemChild(int index, KeyValuePair <TKey, TValue> item, TwoFourTreeNode node = null)
            {
                Debug.Assert(!IsKeyFull);
                Debug.Assert(index >= 0 && index <= _keyNum);
                Debug.Assert(node != null && !IsLeafNode || node == null && IsLeafNode);
                var num = _keyNum - index;

                if (num > 0)
                {
                    Array.Copy(_items, index, _items, index + 1, num);
                    if (node != null)
                    {
                        Array.Copy(_children, index + 1, _children, index + 2, num);
                    }
                }
                _items[index] = item;
                if (node != null)
                {
                    _children[index + 1] = node;
                    node.Parent          = this;
                }
                _keyNum++;
            }
Esempio n. 9
0
 public void AppendItemChild(KeyValuePair <TKey, TValue> item, TwoFourTreeNode node = null) => InsertItemChild(_keyNum, item, node);
Esempio n. 10
0
        private void AdjustNodeWhenRemove(TwoFourTreeNode node)
        {
            var parent = node.Parent;

            Debug.Assert(parent != null);
            var childIndex        = node.GetChildIndex();
            var leftSiblingIndex  = childIndex - 1;
            var rightSiblingIndex = childIndex + 1;

            // If a sibling on either side of this node is a 3-node or a 4-node (thus having more than 1 key)
            if (rightSiblingIndex <= parent.KeyNum && !parent.Children[rightSiblingIndex].IsKeyMin)
            {
                var sibling = parent.Children[rightSiblingIndex];
                var pair    = sibling.RemoveFirstItemChild();
                node.AppendItemChild(parent.Items[childIndex], pair.Node);
                parent.Items[childIndex] = pair.Item;
            }
            else if (leftSiblingIndex >= 0 && !parent.Children[leftSiblingIndex].IsKeyMin)
            {
                var sibling = parent.Children[leftSiblingIndex];
                var pair    = sibling.RemoveLastItemChild();
                node.PushFrontItemChild(parent.Items[leftSiblingIndex], pair.Node);
                parent.Items[leftSiblingIndex] = pair.Item;
            }
            // If all adjacent siblings are 2-nodes
            else if (rightSiblingIndex <= parent.KeyNum && parent.Children[rightSiblingIndex].IsKeyMin)
            {
                node.MergeWithRight(rightSiblingIndex, parent.Children[rightSiblingIndex]);
                if (parent.KeyNum == 0)
                {
                    if (parent == _root)
                    {
                        _root.Invalidate();
                        _root        = node;
                        _root.Parent = null;
                    }
                    else
                    {
                        AdjustNodeWhenRemove(parent);
                    }
                }
            }
            else if (leftSiblingIndex >= 0 && parent.Children[leftSiblingIndex].IsKeyMin)
            {
                var sibling = parent.Children[leftSiblingIndex];
                sibling.MergeWithRight(childIndex, node);
                if (parent.KeyNum == 0)
                {
                    if (parent == _root)
                    {
                        _root.Invalidate();
                        _root        = sibling;
                        _root.Parent = null;
                    }
                    else
                    {
                        AdjustNodeWhenRemove(parent);
                    }
                }
            }

            else
            {
                throw new Exception("cannot reach here!");
            }
        }