Beispiel #1
0
        private LinkedBinaryNode <T> Balance([NotNull] LinkedBinaryNode <T> node)
        {
            // shouldn't be called unless Math.Abs(node.BalanceFactor) > BALANCE_FACTOR
            if (node.BalanceFactor > 1)             // left heavy
            {
                if (node.Left.BalanceFactor < 0)
                {
                    // LR case
                    node.Left = RotateLeft(node.Left);
                    SetHeight(node);
                }

                // LL case
                return(RotateRight(node));
            }

            if (node.BalanceFactor < 1)             // right heavy
            {
                if (node.Right.BalanceFactor > 0)
                {
                    // RL case
                    node.Right = RotateRight(node.Right);
                    SetHeight(node);
                }

                // RR case
                return(RotateLeft(node));
            }

            return(node);
        }
Beispiel #2
0
        /// <inheritdoc />
        public override bool Validate(LinkedBinaryNode <T> node)
        {
            // https://leetcode.com/problems/validate-binary-search-tree/solution/
            if (node == null)
            {
                return(true);
            }

            T    previous = default(T);
            bool isValid = true, started = false;

            Iterate(node, e =>
            {
                if (!started)
                {
                    started  = true;
                    previous = e.Value;
                    return(true);
                }

                isValid = Comparer.IsLessThan(previous, e.Value);
                return(isValid);
            });
            return(isValid);
        }
Beispiel #3
0
 static bool IsBalancedLocal(LinkedBinaryNode <T> node)
 {
     return(node == null ||
            node.IsLeaf ||
            Math.Abs(node.BalanceFactor) <= BALANCE_FACTOR &&
            (node.Left == null ||
             node.Left.IsLeaf ||
             Math.Abs(node.Left.BalanceFactor) <= BALANCE_FACTOR) &&
            (node.Right == null ||
             node.Right.IsLeaf ||
             Math.Abs(node.Right.BalanceFactor) <= BALANCE_FACTOR));
 }
Beispiel #4
0
        /// <inheritdoc />
        public override LinkedBinaryNode <T> FindNearestParent(T value)
        {
            int cmp;
            LinkedBinaryNode <T> parent = null, next = Root;

            while (next != null && (cmp = Comparer.Compare(value, next.Value)) != 0)
            {
                parent = next;
                next   = cmp < 0
                                                        ? next.Left
                                                        : next.Right;
            }

            return(parent);
        }
Beispiel #5
0
        /// <inheritdoc />
        public override void Add(T value)
        {
            if (Root == null)
            {
                Root = MakeNode(value);
                Count++;
                _version++;
                return;
            }

            LinkedBinaryNode <T> parent = null, next = Root;
            // the stack has the same effect as the recursive call but only it's iterative now
            Stack <LinkedBinaryNode <T> > stack = new Stack <LinkedBinaryNode <T> >();
            int order = 0;

            // find a parent. as a general rule: whenever a node's left or right changes, it will be pushed to get updated
            while (next != null)
            {
                order  = Comparer.Compare(value, next.Value);
                parent = next;
                stack.Push(parent);
                next = order < 0
                                                        ? next.Left
                                                        : next.Right;
            }

            Debug.Assert(parent != null, "No parent node found for the new node.");

            LinkedBinaryNode <T> node = MakeNode(value);

            if (order < 0)
            {
                parent !.Left = node;
            }
            else
            {
                parent !.Right = node;
            }

            // update parents
            while (stack.Count > 0)
            {
                SetHeight(stack.Pop());
            }

            Count++;
            _version++;
        }
Beispiel #6
0
        /// <inheritdoc />
        public override void Add(T value)
        {
            if (Root == null)
            {
                Root = MakeNode(value);
                Count++;
                _version++;
                return;
            }

            LinkedBinaryNode <T> parent = null, next = Root;
            // the stack has the same effect as the recursive call but only it's iterative now
            Stack <LinkedBinaryNode <T> > stack = new Stack <LinkedBinaryNode <T> >();

            // find a parent. as a general rule: whenever a node's left or right changes, it will be pushed to get updated
            int order = 0;

            while (next != null)
            {
                order = Comparer.Compare(value, next.Value);
                // duplicate values means nodes will never be balanced!
                if (order == 0)
                {
                    throw new DuplicateKeyException();
                }
                parent = next;
                stack.Push(parent);
                next = order < 0
                                                        ? next.Left
                                                        : next.Right;
            }

            Debug.Assert(parent != null, "No parent node found for the new node.");

            LinkedBinaryNode <T> node = MakeNode(value);

            if (order < 0)
            {
                parent !.Left = node;
            }
            else
            {
                parent !.Right = node;
            }

            // update parents
            while (stack.Count > 0)
            {
                node = stack.Pop();
                SetHeight(node);
                // check the balance
                if (Math.Abs(node.BalanceFactor) <= BALANCE_FACTOR)
                {
                    continue;
                }
                parent = stack.Count > 0
                                                        ? stack.Peek()
                                                        : null;
                bool isLeft = parent != null && ReferenceEquals(parent.Left, node);
                node = Balance(node);

                if (parent == null)
                {
                    Root = node;
                }
                else
                {
                    if (isLeft)
                    {
                        parent.Left = node;
                    }
                    else
                    {
                        parent.Right = node;
                    }

                    SetHeight(parent);
                }
            }

            Count++;
            _version++;
        }
Beispiel #7
0
        /// <inheritdoc />
        public override bool Remove(T value)
        {
            /*
             * Udemy courses sometimes contains garbage! the previous code was wrong or contains
             * at least 2 bugs! Avoid the following implementations for BST or AVL trees:
             * Buggy: Master the Coding Interview Data Structures + Algorithms - Andrei Neagoie.
             * Less than optimal: Mastering Data Structures & Algorithms using C and C++ - Abdul Bari
             *
             * This one is much better but with a small modification because it contains a bug as well
             * for not handling leaf nodes.
             * https://www.geeksforgeeks.org/binary-search-tree-set-3-iterative-delete/?ref=rp
             */
            if (Root == null)
            {
                return(false);
            }

            LinkedBinaryNode <T> parent = null, node = null, next = Root;
            // the deque has the same effect as the recursive call but only it's iterative now
            // will need to use a deque or a linked list instead of the stack because of swap in case 3
            LinkedDeque <LinkedBinaryNode <T> > deque = new LinkedDeque <LinkedBinaryNode <T> >();

            // find the node. as a general rule: whenever a node's left or right changes, it will be pushed to get updated
            while (next != null)
            {
                int order = Comparer.Compare(value, next.Value);

                if (order == 0)
                {
                    node = next;
                    break;
                }

                parent = next;
                deque.Push(parent);
                next = order < 0
                                                        ? next.Left
                                                        : next.Right;
            }

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

            // case 1: node has no children
            if (node.IsLeaf)
            {
                if (parent == null)
                {
                    Root = null;
                }
                else
                {
                    if (ReferenceEquals(parent.Left, node))
                    {
                        parent.Left = null;
                    }
                    else
                    {
                        parent.Right = null;
                    }
                }
            }
            // case 2: node has one child
            else if (node.HasOneChild)
            {
                LinkedBinaryNode <T> newNode = node.Left ?? node.Right;

                if (parent == null)
                {
                    Root = newNode;
                }
                else
                {
                    if (ReferenceEquals(parent.Left, node))
                    {
                        parent.Left = newNode;
                    }
                    else
                    {
                        parent.Right = newNode;
                    }
                }
            }
            // case 3: node has 2 children
            else
            {
                // find the right child's left most child (successor)
                LinkedBinaryNode <T> leftMostParent = null;
                LinkedBinaryNode <T> successor      = node.Right;

                while (successor.Left != null)
                {
                    leftMostParent = successor;
                    deque.Push(leftMostParent);
                    successor = successor.Left;
                }

                /*
                 * if there is a left-most for the node's right node, then
                 * move its right to its parent's left.
                 */
                if (leftMostParent != null)
                {
                    leftMostParent.Left = successor.Right;

                    // insert the node because it will be swapped later with the successor
                    if (parent != null)
                    {
                        deque.PushBefore(parent, node);
                    }
                    else
                    {
                        deque.PushLast(node);
                    }
                }
                // Otherwise, move the successor's right to the node's right
                else
                {
                    node.Right = successor.Right;
                    deque.Push(node);
                }

                // swap the value with the successor
                node.Swap(successor);
            }

            // update parents
            while (deque.Count > 0)
            {
                node = deque.Pop();
                SetHeight(node);
                // check the balance
                if (Math.Abs(node.BalanceFactor) <= BALANCE_FACTOR)
                {
                    continue;
                }
                parent = deque.Count > 0
                                                        ? deque.PeekTail()
                                                        : null;
                bool isLeft = parent != null && ReferenceEquals(parent.Left, node);
                node = Balance(node);

                if (parent == null)
                {
                    Root = node;
                }
                else
                {
                    if (isLeft)
                    {
                        parent.Left = node;
                    }
                    else
                    {
                        parent.Right = node;
                    }

                    SetHeight(parent);
                }
            }

            Count--;
            _version++;
            return(true);
        }