public RedBlackTree(string strIdentifier) { intHashCode = rand.Next(); this.strIdentifier = strIdentifier; // set up the sentinel node. the sentinel node is the key to a successfull // implementation and for understanding the red-black tree properties. if (sentinelNode == null) { sentinelNode = new RedBlackNode(); sentinelNode.Left = null; sentinelNode.Right = null; sentinelNode.Parent = null; sentinelNode.Color = RedBlackNode.BLACK; } rbTree = sentinelNode; lastNodeFound = sentinelNode; }
///<summary> /// RotateRight /// Rebalance the tree by rotating the nodes to the right ///</summary> public void RotateRight(RedBlackNode x) { // pushing node x down and to the Right to balance the tree. x's Left child (y) // replaces x (since x < y), and y's Right child becomes x's Left child // (since it's < x but > y). RedBlackNode y = x.Left; // get x's Left node, this becomes y // set x's Right link x.Left = y.Right; // y's Right child becomes x's Left child // modify parents if (y.Right != sentinelNode) { y.Right.Parent = x; // sets y's Right Parent to x } if (y != sentinelNode) { y.Parent = x.Parent; // set y's Parent to x's Parent } if (x.Parent != null) // null=rbTree, could also have used rbTree { // determine which side of it's Parent x was on if (x == x.Parent.Right) { x.Parent.Right = y; // set Right Parent to y } else { x.Parent.Left = y; // set Left Parent to y } } else { rbTree = y; // at rbTree, set it to y } // link x and y y.Right = x; // put x on y's Right if (x != sentinelNode) // set y as x's Parent { x.Parent = y; } }
///<summary> /// GetMaxKey /// Returns the maximum key value ///<summary> public IComparable GetMaxKey() { RedBlackNode treeNode = rbTree; if (treeNode == null) { throw(new Exception("RedBlack tree is empty -- treeNode==null")); } if (treeNode == sentinelNode) { throw(new Exception("RedBlack tree is empty -- treeNode == sentinelNode")); } // traverse to the extreme right to find the largest key while (treeNode.Right != sentinelNode) { treeNode = treeNode.Right; } lastNodeFound = treeNode; return(treeNode.Key); }
///<summary> /// NextElement ///</summary> public object NextElement() { if (stack.Count == 0) { throw(new Exception("Element not found")); } // the top of stack will always have the next item // get top of stack but don't remove it as the next nodes in sequence // may be pushed onto the top // the stack will be popped after all the nodes have been returned RedBlackNode node = (RedBlackNode)stack.Peek(); //next node in sequence if (ascending) { if (node.Right == RedBlackTree.sentinelNode) { // yes, top node is lowest node in subtree - pop node off stack RedBlackNode tn = (RedBlackNode)stack.Pop(); // peek at right node's parent // get rid of it if it has already been used while (HasMoreElements() && ((RedBlackNode)stack.Peek()).Right == tn) { tn = (RedBlackNode)stack.Pop(); } } else { // find the next items in the sequence // traverse to left; find lowest and push onto stack RedBlackNode tn = node.Right; while (tn != RedBlackTree.sentinelNode) { stack.Push(tn); tn = tn.Left; } } } else // descending, same comments as above apply { if (node.Left == RedBlackTree.sentinelNode) { // walk the tree RedBlackNode tn = (RedBlackNode)stack.Pop(); while (HasMoreElements() && ((RedBlackNode)stack.Peek()).Left == tn) { tn = (RedBlackNode)stack.Pop(); } } else { // determine next node in sequence // traverse to left subtree and find greatest node - push onto stack RedBlackNode tn = node.Left; while (tn != RedBlackTree.sentinelNode) { stack.Push(tn); tn = tn.Right; } } } // the following is for .NET compatibility (see MoveNext()) Key = node.Key; Value = node.Data; // ******** testing only ******** try { parentKey = node.Parent.Key; // testing only } catch //(Exception e) { parentKey = 0; } if (node.Color == 0) // testing only { Color = "Red"; } else { Color = "Black"; } // ******** testing only ******** return(keys == true ? node.Key : node.Data); }
///<summary> /// Clear /// Empties or clears the tree ///<summary> public void Clear() { rbTree = sentinelNode; intCount = 0; }
///<summary> /// RestoreAfterDelete /// 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 RestoreAfterDelete(RedBlackNode x) { // maintain Red-Black tree balance after deleting node RedBlackNode y; while (x != rbTree && x.Color == RedBlackNode.BLACK) { if (x == x.Parent.Left) // determine sub tree from parent { y = x.Parent.Right; // y is x's sibling if (y.Color == RedBlackNode.RED) { // x is black, y is red - make both black and rotate y.Color = RedBlackNode.BLACK; x.Parent.Color = RedBlackNode.RED; RotateLeft(x.Parent); y = x.Parent.Right; } if (y.Left.Color == RedBlackNode.BLACK && y.Right.Color == RedBlackNode.BLACK) { // children are both black y.Color = RedBlackNode.RED; // change parent to red x = x.Parent; // move up the tree } else { if (y.Right.Color == RedBlackNode.BLACK) { y.Left.Color = RedBlackNode.BLACK; y.Color = RedBlackNode.RED; RotateRight(y); y = x.Parent.Right; } y.Color = x.Parent.Color; x.Parent.Color = RedBlackNode.BLACK; y.Right.Color = RedBlackNode.BLACK; RotateLeft(x.Parent); x = rbTree; } } else { // right subtree - same as code above with right and left swapped y = x.Parent.Left; if (y.Color == RedBlackNode.RED) { y.Color = RedBlackNode.BLACK; x.Parent.Color = RedBlackNode.RED; RotateRight(x.Parent); y = x.Parent.Left; } if (y.Right.Color == RedBlackNode.BLACK && y.Left.Color == RedBlackNode.BLACK) { y.Color = RedBlackNode.RED; x = x.Parent; } else { if (y.Left.Color == RedBlackNode.BLACK) { y.Right.Color = RedBlackNode.BLACK; y.Color = RedBlackNode.RED; RotateLeft(y); y = x.Parent.Left; } y.Color = x.Parent.Color; x.Parent.Color = RedBlackNode.BLACK; y.Left.Color = RedBlackNode.BLACK; RotateRight(x.Parent); x = rbTree; } } } x.Color = RedBlackNode.BLACK; }
///<summary> /// Delete /// Delete a node from the tree and restore red black properties ///<summary> private void Delete(RedBlackNode z) { // 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 RedBlackNode x = new RedBlackNode(); // work node to contain the replacement node RedBlackNode y; // work node // find the replacement node (the successor to x) - the node one with // at *most* one child. if (z.Left == sentinelNode || z.Right == sentinelNode) { y = z; // node has sentinel as a child } else { // z has two children, find replacement node which will // be the leftmost node greater than z y = z.Right; // traverse right subtree while (y.Left != sentinelNode) // to find next node in sequence { y = y.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. if (y.Left != sentinelNode) { x = y.Left; } else { x = y.Right; } // replace x's parent with y's parent and // link x to proper subtree in parent // this removes y from the chain x.Parent = y.Parent; if (y.Parent != null) { if (y == y.Parent.Left) { y.Parent.Left = x; } else { y.Parent.Right = x; } } else { rbTree = x; // make x the root node } // copy the values from y (the replacement node) to the node being deleted. // note: this effectively deletes the node. if (y != z) { z.Key = y.Key; z.Data = y.Data; } if (y.Color == RedBlackNode.BLACK) { RestoreAfterDelete(x); } lastNodeFound = sentinelNode; }
///<summary> /// RestoreAfterInsert /// 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 RestoreAfterInsert(RedBlackNode x) { // x and y are used as variable names for brevity, in a more formal // implementation, you should probably change the names RedBlackNode y; // maintain red-black tree properties after adding x while (x != rbTree && x.Parent.Color == RedBlackNode.RED) { // Parent node is .Colored red; if (x.Parent == x.Parent.Parent.Left) // determine traversal path { // is it on the Left or Right subtree? y = x.Parent.Parent.Right; // get uncle if (y != null && y.Color == RedBlackNode.RED) { // uncle is red; change x's Parent and uncle to black x.Parent.Color = RedBlackNode.BLACK; y.Color = RedBlackNode.BLACK; // grandparent must be red. Why? Every red node that is not // a leaf has only black children x.Parent.Parent.Color = RedBlackNode.RED; x = x.Parent.Parent; // continue loop with grandparent } else { // uncle is black; determine if x is greater than Parent if (x == x.Parent.Right) { // yes, x is greater than Parent; rotate Left // make x a Left child x = x.Parent; RotateLeft(x); } // no, x is less than Parent x.Parent.Color = RedBlackNode.BLACK; // make Parent black x.Parent.Parent.Color = RedBlackNode.RED; // make grandparent black RotateRight(x.Parent.Parent); // rotate right } } else { // x's Parent is on the Right subtree // this code is the same as above with "Left" and "Right" swapped y = x.Parent.Parent.Left; if (y != null && y.Color == RedBlackNode.RED) { x.Parent.Color = RedBlackNode.BLACK; y.Color = RedBlackNode.BLACK; x.Parent.Parent.Color = RedBlackNode.RED; x = x.Parent.Parent; } else { if (x == x.Parent.Left) { x = x.Parent; RotateRight(x); } x.Parent.Color = RedBlackNode.BLACK; x.Parent.Parent.Color = RedBlackNode.RED; RotateLeft(x.Parent.Parent); } } } rbTree.Color = RedBlackNode.BLACK; // rbTree should always be black }