Ejemplo n.º 1
0
        private TNode FixTree(AvlStackNode <TNode> stack, TNode node)
        {
            // Could be null on delete possibly.
            if (IsNull(node))
            {
                return(node);
            }

            while (stack != null)
            {
                var childNode = node;

                node = stack.Node;

                // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
                if (stack.ImmediateChangeInBalanceFactor == 1)
                {
                    node = SetLeft(node, childNode);
                }
                else
                {
                    node = SetRight(node, childNode);
                }

                stack = stack.Previous;
            }

            return(node);
        }
Ejemplo n.º 2
0
        private TNode Find(TNode root, TKey key, out AvlStackNode <TNode> stack)
        {
            stack = null;

            var node = root;

            while (!IsNull(node))
            {
                var compareResult = CompareKeys(GetKey(node), key);

                if (compareResult == 0)
                {
                    break;
                }

                if (compareResult < 0)
                {
                    stack = new AvlStackNode <TNode>()
                    {
                        // remove something on the right side, so net change is 1, or addition to left side
                        ImmediateChangeInBalanceFactor = 1,
                        Node     = node,
                        Previous = stack
                    };

                    node = GetRight(node);
                }
                else if (compareResult > 0 || SupportsDuplicateKeys())
                {
                    stack = new AvlStackNode <TNode>()
                    {
                        // remove something on the left side, so net change is -1, or addition to right side
                        ImmediateChangeInBalanceFactor = -1,
                        Node     = node,
                        Previous = stack
                    };

                    node = GetLeft(node);
                }
            }

            return(node);
        }
Ejemplo n.º 3
0
        private TNode RotateSmallestUp(TNode node)
        {
            AvlStackNode <TNode> stack = null;

            var preceding = GetLeft(node);

            while (preceding != null)
            {
                stack = new AvlStackNode <TNode>()
                {
                    Node     = node,
                    Previous = stack
                };

                // since the recursive algorithm passes in preceding, we need to make the node equal to preceding.
                node = preceding;

                // update the preceding calculation for the next iteration of the while loop.
                preceding = GetLeft(node);
            }

            preceding = node;

            // reached base case of the recursive algorithm and the preceding node is now null.

            while (stack != null)
            {
                node = stack.Node;

                node = SetLeft(node, preceding);

                preceding = RotateRight(node);

                stack = stack.Previous;
            }

            return(preceding);
        }
Ejemplo n.º 4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="stack"></param>
        /// <param name="node"></param>
        /// <param name="parentalChange">The type of previous change determines the parantal change.</param>
        /// <returns></returns>
        private TNode BalanceTreeAfterDeletion(AvlStackNode <TNode> stack, TNode node, int parentalChange)
        {
            // Approach
            // 0) Set the new balance factor based upon the immediate change from the previous logic.
            // 1) Set Edge which always has to be updated as the algorithm moves up the stack due to the collection nodes being immutable.
            // 2) Adjust balance factor on the node we are currently based upon rules.
            while (stack != null)
            {
                var child = node;

                node = stack.Node;

                if (stack.ImmediateChangeInBalanceFactor == -1)
                {
                    // CASE 1.2a - A leaf node is being deleted
                    node = SetLeft(node, child);
                }
                else
                {
                    // CASE 1.2b - A leaf node is being deleted
                    node = SetRight(node, child);
                }

                var newTheoreticalBalanceFactor = GetBalanceFactor(node) + parentalChange;

                switch (newTheoreticalBalanceFactor)
                {
                case 2:
                {
                    var singleRotate = GetBalanceFactor(GetLeft(node)) == 1;          // needs to be reverse of the insert

                    #region Notes

                    // Note: the balance factor logic is specific to the sub
                    //       case.  The logic is not setup to work correctly
                    //       if you calling rotate left and then rotate right.
                    //       This is because the logic is optimized and the
                    //       Rotate right does not consider this particular right
                    //       rotation needed by this rotation sequence.

                    #endregion

                    node = singleRotate ? RotateRight(node) : RotateLeftRight(node);

                    break;
                }

                case -2:
                {
                    var singleRotate = GetBalanceFactor(GetRight(node)) == -1;         // needs to be reverse of the insert

                    // Note: the balance factor logic is specific to the sub
                    //       case.  The logic is not setup to work correctly
                    //       if you calling rotate right and then rotate left.
                    //       This is because the logic is optimized and the
                    //       Rotate Left does not consider this particular left
                    //       rotation needed by this rotation sequence.
                    node = singleRotate ? RotateLeft(node) : RotateRightLeft(node);

                    break;
                }

                case 0:
                {
                    // part of AVL algoirthm
                    node = SetBalanceFactor(node, newTheoreticalBalanceFactor);

                    break;
                }

                case 1:
                case -1:
                {
                    // Since the balance equals 1 or -1, nothing really changed, we are done.
                    break;         //return FixTree(stack, node);
                }
                }

                // This means the curent node needs to be the node in the stack;
                stack = stack.Previous;

                if (stack != null)
                {
                    parentalChange = stack.ImmediateChangeInBalanceFactor;
                }
            }

            return(node);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Adds a new node to the tree and returns the new root of the tree.
        /// </summary>
        /// <param name="root"></param>
        /// <param name="newNode"></param>
        /// <param name="compareValue"></param>
        /// <note>Having the comparison value passsed in allows for the method to be more easily tested.   We can just pick various compare values and see how the tree responds.</note>
        /// <returns>The new root of the tree.</returns>
        public TNode AddNode(TNode root, TNode newNode)
        {
            if (IsNull(root))
            {
                return(newNode);
            }

            if (IsNull(newNode))
            {
                return(root);
            }

            var node = root;

            AvlStackNode <TNode> stack = null;

            int direction;

            TNode nextNode;

            // While there is a node to insert
            while (true)
            {
                var comparisonValue = Compare(node, newNode);

                if (comparisonValue > 0 || (SupportsDuplicateKeys() && comparisonValue == 0))
                {
                    nextNode = GetLeft(node);

                    direction = 1;

                    if (IsNull(nextNode))
                    {
                        node = SetLeft(node, newNode);

                        break;
                    }
                }
                else if (comparisonValue < 0)
                {
                    nextNode = GetRight(node);

                    direction = -1;

                    if (IsNull(nextNode))
                    {
                        node = SetRight(node, newNode);

                        break;
                    }
                }
                else
                {
                    return(HandleDuplicateException(root, node, newNode));
                }

                stack = new AvlStackNode <TNode>()
                {
                    ImmediateChangeInBalanceFactor = direction,
                    Node     = node,
                    Previous = stack
                };

                node = nextNode;
            }


            // adjust balance factor on the current node
            var newBalanceFactor = GetBalanceFactor(node) + direction;

            node = SetBalanceFactor(node, newBalanceFactor);

            return(BalanceTree(stack, node, newBalanceFactor)); // If I am adding a new node to the right of the parent, the parent balance factor will increase by one.

            // Found a node that is the same
        }
Ejemplo n.º 6
0
        private TNode RemoveNode(TNode node, AvlStackNode <TNode> stack)
        {
            // CASE 1: If has no children delete the root.  We know this is the root as there is no stack.
            if (stack == null)
            {
                // CASE 1.1 - The root node is being deleted.
                return(NullNode());
            }

            var left  = GetLeft(node);
            var right = GetRight(node);

            TNode newChild;

            if (!IsNull(left) && !IsNull(right))
            {
                right = RotateSmallestUp(right);

                newChild = SetLeft(right, GetLeft(node), GetBalanceFactor(right) - 1);

                return(BalanceTreeAfterDeletion(stack, newChild, -1));
            }

            if (IsNull(left))
            {
                // LEFT is NULL and RIGHT is NULL
                if (IsNull(right))
                {
                    var previousStack = stack.Previous;

                    if (previousStack == null)
                    {
                        return(BalanceTreeAfterDeletion(stack, right, stack.ImmediateChangeInBalanceFactor));
                    }

                    newChild = stack.Node;
                    int   parentalChange;
                    TNode newChildSibling;

                    if (stack.ImmediateChangeInBalanceFactor == -1)
                    {
                        newChild = SetLeft(newChild, right, GetBalanceFactor(stack.Node) + stack.ImmediateChangeInBalanceFactor);

                        newChildSibling = GetRight(newChild);
                    }
                    else
                    {
                        newChild = SetRight(newChild, right, GetBalanceFactor(stack.Node) + stack.ImmediateChangeInBalanceFactor);

                        newChildSibling = GetLeft(newChild);
                    }

                    parentalChange = IsNull(newChildSibling) ? previousStack.ImmediateChangeInBalanceFactor : 0;

                    // could be assigned either right or left, does not matter, both are null.
                    return(BalanceTreeAfterDeletion(previousStack, newChild, parentalChange));
                }

                // CASE 2a - Node with one child being deleted - left is null, right not null
                newChild = DuplicateNodeFromNode(right);

                return(BalanceTreeAfterDeletion(stack, newChild, stack.ImmediateChangeInBalanceFactor));
            }

            // CASE 2b - Node with one child being deleted - left is not null, right is null
            newChild = DuplicateNodeFromNode(left);

            return(BalanceTreeAfterDeletion(stack, newChild, stack.ImmediateChangeInBalanceFactor));
        }
Ejemplo n.º 7
0
        private TNode BalanceTree(AvlStackNode <TNode> stack, TNode parent, int newTheoreticalBalanceFactorForParent)
        {
            while (newTheoreticalBalanceFactorForParent != 0 && stack != null)
            {
                // STEP 1: CHECK IF EDGE NEEDS TO BE SETUP - Has to be first due to immutability
                // This needs to be first since we might need to estabalish / update a edge prior to rotations
                // since the AVL tree is immutable.
                if (newTheoreticalBalanceFactorForParent == 1 || newTheoreticalBalanceFactorForParent == -1)
                {
                    // immutability forces this
                    var grandparent = stack.Node;

                    // no parent node forces this so we cannot just look up the data structure
                    newTheoreticalBalanceFactorForParent = stack.ImmediateChangeInBalanceFactor;

                    // no parent node forces.
                    stack = stack.Previous;

                    // This is a neccessity since we are using

                    // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
                    if (newTheoreticalBalanceFactorForParent == 1)
                    {
                        // immutability forces this - rotations fail without this being set.
                        parent = SetLeft(grandparent, parent);
                    }
                    else
                    {
                        // immutability forces this - rotations fail without this being set.
                        parent = SetRight(grandparent, parent);
                    }

                    // part of AVL algoirthm
                    newTheoreticalBalanceFactorForParent = GetBalanceFactor(parent) + newTheoreticalBalanceFactorForParent;

                    // part of AVL algoirthm
                    parent = SetBalanceFactor(parent, newTheoreticalBalanceFactorForParent);
                }

                // STEP 2: CHECK IF ROTATION NEEDS TO BE PERFORMED

                switch (newTheoreticalBalanceFactorForParent)
                {
                case 2:
                {
                    var singleRotate = GetBalanceFactor(GetLeft(parent)) == 1;

                    #region Notes

                    // Note: the balance factor logic is specific to the sub
                    //       case.  The logic is not setup to work correctly
                    //       if you calling rotate left and then rotate right.
                    //       This is because the logic is optimized and the
                    //       Rotate right does not consider this particular right
                    //       rotation needed by this rotation sequence.

                    #endregion

                    parent = singleRotate ? RotateRight(parent) : RotateLeftRight(parent);

                    newTheoreticalBalanceFactorForParent = GetBalanceFactor(parent);

                    break;
                }

                case -2:
                {
                    var singleRotate = GetBalanceFactor(GetRight(parent)) == -1;

                    // Note: the balance factor logic is specific to the sub
                    //       case.  The logic is not setup to work correctly
                    //       if you calling rotate right and then rotate left.
                    //       This is because the logic is optimized and the
                    //       Rotate Left does not consider this particular left
                    //       rotation needed by this rotation sequence.
                    parent = singleRotate ? RotateLeft(parent) : RotateRightLeft(parent);

                    newTheoreticalBalanceFactorForParent = GetBalanceFactor(parent);

                    break;
                }
                }
            }

            return(FixTree(stack, parent));
        }