public override bool IsBalanced() { if (Root == null || Root.IsLeaf) { return(true); } // using levelOrder traversal // Root-Left-Right (Queue) Queue <RedBlackNode <T> > queue = new Queue <RedBlackNode <T> >(GetCapacityForQueueing(this)); // Start at the root queue.Enqueue(Root); while (queue.Count > 0) { RedBlackNode <T> current = queue.Dequeue(); // Queue the next nodes if (current.Left != null) { if (!IsBalancedLocal(current.Left, current)) { return(false); } queue.Enqueue(current.Left); } if (current.Right != null) { if (!IsBalancedLocal(current.Right, current)) { return(false); } queue.Enqueue(current.Right); } } return(true);
/// <summary> /// Validates the node and its children. /// </summary> /// <param name="node"></param> /// <returns></returns> public override bool Validate(RedBlackNode <T> node) { 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); }
public override bool Remove(T value) { if (Root == null) { return(false); } /* * Search for a node and then find its successor then copy the item from the successor * to the matching node and delete the successor. * * If a node doesn't have a successor, we can replace it with its left child (if not empty.) * or delete the matching node. * * In top-down implementation, it is important to make sure the node to be deleted is not a 2-node. */ RedBlackNode <T> current = Root, parent = null, grandParent = null, match = null, parentOfMatch = null; bool foundMatch = false; while (current != null) { if (Is2Node(current)) { if (parent == null) { current.Color = true; } else { RedBlackNode <T> sibling = GetSibling(current, parent); if (sibling.Color) { /* * If parent is a 3-node, flip the orientation of the red link. * We can achieve this by a single rotation. This case is converted * to one of other cased below. */ Debug.Assert(!parent.Color, "parent must be a black node!"); if (ReferenceEquals(parent.Right, sibling)) { RotateLeft(parent); } else { RotateRight(parent); } parent.Color = true; sibling.Color = false; // sibling becomes child of grandParent or root after rotation. Update link from grandParent or root. ReplaceChildOfNodeOrRoot(grandParent, parent, sibling); // sibling will become grandParent of current node grandParent = sibling; if (ReferenceEquals(parent, match)) { parentOfMatch = sibling; } // update sibling, this is necessary for following processing sibling = (ReferenceEquals(parent.Left, current) ? parent.Right : parent.Left) ?? throw new Exception("Sibling must not be null!"); } Debug.Assert(!sibling.Color, "Sibling must be black!"); if (Is2Node(sibling)) { Merge2Nodes(parent, current, sibling); } else { /* * current is a 2-node and sibling is either a 3-node or a 4-node. * We can change the color of current to red by some rotation. */ RedBlackNode <T> newGrandParent; Debug.Assert(IsRed(sibling.Left) || IsRed(sibling.Right), "sibling must have at least one red child"); if (IsRed(sibling.Left)) { if (ReferenceEquals(parent.Left, current)) { // R L case Debug.Assert(parent.Right == sibling, "sibling must be left child of parent!"); Debug.Assert(sibling.Left.Color, "Left child of sibling must be red!"); newGrandParent = RotateRightLeft(parent); } else { // R case Debug.Assert(parent.Left == sibling, "sibling must be left child of parent!"); Debug.Assert(sibling.Left.Color, "Left child of sibling must be red!"); sibling.Left.Color = false; newGrandParent = RotateRight(parent); } } else { if (ReferenceEquals(parent.Left, current)) { // L case Debug.Assert(parent.Right == sibling, "sibling must be left child of parent!"); Debug.Assert(sibling.Right.Color, "Right child of sibling must be red!"); sibling.Right.Color = false; newGrandParent = RotateLeft(parent); } else { // L R case Debug.Assert(parent.Left == sibling, "sibling must be left child of parent!"); Debug.Assert(sibling.Right.Color, "Right child of sibling must be red!"); newGrandParent = RotateLeftRight(parent); } } newGrandParent.Color = parent.Color; parent.Color = false; current.Color = true; ReplaceChildOfNodeOrRoot(grandParent, parent, newGrandParent); if (parent == match) { parentOfMatch = newGrandParent; } } } } // we don't need to compare any more once we found the match int order = foundMatch ? -1 : Comparer.Compare(value, current.Value); if (order == 0) { // save the matching node foundMatch = true; match = current; parentOfMatch = parent; } grandParent = parent; parent = current; // continue the search in right sub-tree after we find a match current = order < 0 ? current.Left : current.Right; } // move successor to the matching node position and replace links if (match != null) { ReplaceNode(match, parentOfMatch, parent, grandParent); Count--; _version++; } if (Root != null) { Root.Color = false; } return(true); }
/// <inheritdoc /> public override void Add(T value) { if (Root == null) { Root = MakeNode(value); Root.Color = false; Count++; _version++; return; } RedBlackNode <T> current = Root, parent = null, grandParent = null, greatGrandParent = null; int order = 0; /* * If we can guarantee the node we found is not a 4-node, it would be easy to do insertion. * We split 4-nodes along the search path. */ // find a parent while (current != null) { order = Comparer.Compare(value, current.Value); // duplicate values means nodes will never be balanced! if (order == 0) { // We could have changed root node to red during the search process. Root needs to be set to black. Root.Color = false; throw new DuplicateKeyException(); } // split a 4-node into two 2-nodes if (Is4Node(current)) { Split4Node(current); // We could have introduced two consecutive red nodes after split. Fix that by rotation. if (IsRed(parent) && grandParent != null) { Balance(current, ref parent, grandParent, greatGrandParent); } } greatGrandParent = grandParent; grandParent = parent; parent = current; current = order < 0 ? current.Left : current.Right; } Debug.Assert(parent != null, "No parent node found for the new node."); RedBlackNode <T> node = MakeNode(value); if (order < 0) { parent !.Left = node; } else { parent !.Right = node; } // the new node will be red, so we will need to adjust the colors if parent node is also red if (parent.Color && grandParent != null) { Balance(node, ref parent, grandParent, greatGrandParent); } // Root node is always black Root.Color = false; Count++; _version++; }