public TKey GetMaxKey() { RedBlackNode <TKey, TValue> workNode = _treeBaseNode; if (workNode == null || workNode == SentinelNode) { throw (new RedBlackException(Properties.Resources.ExceptionTreeIsEmpty)); } // traverse to the extreme right to find the largest key while (workNode.Right != SentinelNode) { workNode = workNode.Right; } _lastNodeFound = workNode; return(workNode.Key); }
///<summary> /// Balance Tree After Insert /// Additions to red-black trees usually destroy the red-black /// properties. Examine the tree and restore. Rotations are normally /// required to restore it ///</summary> private void BalanceTreeAfterInsert(RedBlackNode <TKey, TValue> insertedNode) { // x and y are used as variable names for brevity, in a more formal // implementation, you should probably change the names // maintain red-black tree properties after adding newNode while (insertedNode != _treeBaseNode && insertedNode.Parent.Color == RedBlackNodeType.Red) { // Parent node is .Colored red; RedBlackNode <TKey, TValue> workNode; if (insertedNode.Parent == insertedNode.Parent.Parent.Left) // determine traversal path { // is it on the Left or Right subtree? workNode = insertedNode.Parent.Parent.Right; // get uncle if (workNode != null && workNode.Color == RedBlackNodeType.Red) { // uncle is red; change x's Parent and uncle to black insertedNode.Parent.Color = RedBlackNodeType.Black; workNode.Color = RedBlackNodeType.Black; // grandparent must be red. Why? Every red node that is not // a leaf has only black children insertedNode.Parent.Parent.Color = RedBlackNodeType.Red; insertedNode = insertedNode.Parent.Parent; // continue loop with grandparent } else { // uncle is black; determine if newNode is greater than Parent if (insertedNode == insertedNode.Parent.Right) { // yes, newNode is greater than Parent; rotate Left // make newNode a Left child insertedNode = insertedNode.Parent; RotateLeft(insertedNode); } // no, newNode is less than Parent insertedNode.Parent.Color = RedBlackNodeType.Black; // make Parent black insertedNode.Parent.Parent.Color = RedBlackNodeType.Red; // make grandparent black RotateRight(insertedNode.Parent.Parent); // rotate right } } else { // newNode's Parent is on the Right subtree // this code is the same as above with "Left" and "Right" swapped workNode = insertedNode.Parent.Parent.Left; if (workNode != null && workNode.Color == RedBlackNodeType.Red) { insertedNode.Parent.Color = RedBlackNodeType.Black; workNode.Color = RedBlackNodeType.Black; insertedNode.Parent.Parent.Color = RedBlackNodeType.Red; insertedNode = insertedNode.Parent.Parent; } else { if (insertedNode == insertedNode.Parent.Left) { insertedNode = insertedNode.Parent; RotateRight(insertedNode); } insertedNode.Parent.Color = RedBlackNodeType.Black; insertedNode.Parent.Parent.Color = RedBlackNodeType.Red; RotateLeft(insertedNode.Parent.Parent); } } } _treeBaseNode.Color = RedBlackNodeType.Black; // rbTree should always be black }
///<summary> /// BalanceTreeAfterDelete /// Deletions from red-black trees may destroy the red-black /// properties. Examine the tree and restore. Rotations are normally /// required to restore it ///</summary> private void BalanceTreeAfterDelete(RedBlackNode <TKey, TValue> linkedNode) { // maintain Red-Black tree balance after deleting node while (linkedNode != _treeBaseNode && linkedNode.Color == RedBlackNodeType.Black) { RedBlackNode <TKey, TValue> workNode; // determine sub tree from parent if (linkedNode == linkedNode.Parent.Left) { // y is x's sibling workNode = linkedNode.Parent.Right; if (workNode.Color == RedBlackNodeType.Red) { // x is black, y is red - make both black and rotate linkedNode.Parent.Color = RedBlackNodeType.Red; workNode.Color = RedBlackNodeType.Black; RotateLeft(linkedNode.Parent); workNode = linkedNode.Parent.Right; } if (workNode.Left.Color == RedBlackNodeType.Black && workNode.Right.Color == RedBlackNodeType.Black) { // children are both black // change parent to red workNode.Color = RedBlackNodeType.Red; // move up the tree linkedNode = linkedNode.Parent; } else { if (workNode.Right.Color == RedBlackNodeType.Black) { workNode.Left.Color = RedBlackNodeType.Black; workNode.Color = RedBlackNodeType.Red; RotateRight(workNode); workNode = linkedNode.Parent.Right; } linkedNode.Parent.Color = RedBlackNodeType.Black; workNode.Color = linkedNode.Parent.Color; workNode.Right.Color = RedBlackNodeType.Black; RotateLeft(linkedNode.Parent); linkedNode = _treeBaseNode; } } else { // right subtree - same as code above with right and left swapped workNode = linkedNode.Parent.Left; if (workNode.Color == RedBlackNodeType.Red) { linkedNode.Parent.Color = RedBlackNodeType.Red; workNode.Color = RedBlackNodeType.Black; RotateRight(linkedNode.Parent); workNode = linkedNode.Parent.Left; } if (workNode.Right.Color == RedBlackNodeType.Black && workNode.Left.Color == RedBlackNodeType.Black) { workNode.Color = RedBlackNodeType.Red; linkedNode = linkedNode.Parent; } else { if (workNode.Left.Color == RedBlackNodeType.Black) { workNode.Right.Color = RedBlackNodeType.Black; workNode.Color = RedBlackNodeType.Red; RotateLeft(workNode); workNode = linkedNode.Parent.Left; } workNode.Color = linkedNode.Parent.Color; linkedNode.Parent.Color = RedBlackNodeType.Black; workNode.Left.Color = RedBlackNodeType.Black; RotateRight(linkedNode.Parent); linkedNode = _treeBaseNode; } } } linkedNode.Color = RedBlackNodeType.Black; }
///<summary> /// Delete /// Delete a node from the tree and restore red black properties ///</summary> private void Delete(RedBlackNode <TKey, TValue> deleteNode) { // A node to be deleted will be: // 1. a leaf with no children // 2. have one child // 3. have two children // If the deleted node is red, the red black properties still hold. // If the deleted node is black, the tree needs rebalancing // work node RedBlackNode <TKey, TValue> workNode; // find the replacement node (the successor to x) - the node one with // at *most* one child. if (deleteNode.Left == SentinelNode || deleteNode.Right == SentinelNode) { // node has sentinel as a child workNode = deleteNode; } else { // z has two children, find replacement node which will // be the leftmost node greater than z // traverse right subtree workNode = deleteNode.Right; // to find next node in sequence while (workNode.Left != SentinelNode) { workNode = workNode.Left; } } // at this point, y contains the replacement node. it's content will be copied // to the valules in the node to be deleted // x (y's only child) is the node that will be linked to y's old parent. RedBlackNode <TKey, TValue> linkedNode = workNode.Left != SentinelNode ? workNode.Left : workNode.Right; // replace x's parent with y's parent and // link x to proper subtree in parent // this removes y from the chain linkedNode.Parent = workNode.Parent; if (workNode.Parent != null) { if (workNode == workNode.Parent.Left) { workNode.Parent.Left = linkedNode; } else { workNode.Parent.Right = linkedNode; } } else { // make x the root node _treeBaseNode = linkedNode; } // copy the values from y (the replacement node) to the node being deleted. // note: this effectively deletes the node. if (workNode != deleteNode) { deleteNode.Key = workNode.Key; deleteNode.Data = workNode.Data; } if (workNode.Color == RedBlackNodeType.Black) { BalanceTreeAfterDelete(linkedNode); } _lastNodeFound = SentinelNode; Interlocked.Decrement(ref _count); InvokeOnRemove(new RedBlackEventArgs <TKey, TValue> { Item = deleteNode.Data, Key = deleteNode.Key }); }
///<summary> /// Clear /// Empties or clears the tree ///</summary> public void Clear() { _treeBaseNode = SentinelNode; _count = 0; InvokeOnClear(new EventArgs()); }