/// <summary> /// Used by AddTree before reinsertion of the node /// </summary> internal virtual void ClearRelations() { mColor = RBTreeColor.Black; mLeft = null; mRight = null; mParent = null; }
///<summary> ///Return a pointer to the largest key smaller than x /// protected RBTreeNodeBase <T, P> Predecessor(RBTreeNodeBase <T, P> x) { RBTreeNodeBase <T, P> y; if (x.mLeft != null) { // If left is not NULL then go left one and // then keep going right until we find a node with // no right pointer. for (y = x.mLeft; y.mRight != null; y = y.mRight) { ; } } else { // Go up the tree until we get to a node that is on the // right of its parent (or the root) and then return the // parent. y = x.mParent; while (y != null && x == y.mLeft) { x = y; y = y.mParent; } } return(y); }
///<summary> ///Tree constructor ///</summary> public RBTreeBase(bool unique) { mRoot = null; mComparer = Comparer <T> .Default; mCount = 0; mUnique = unique; }
///<summary> ///Tree constructor with comparer ///</summary> public RBTreeBase(IComparer <T> aComparer, bool unique) { mRoot = null; mComparer = aComparer; mCount = 0; mUnique = unique; }
/// <summary> /// This method was added by Dmitriano. Re-adds root element to the three /// after Comparer has been changed. /// </summary> /// <param name="node"></param> void AddTree(RBTreeNodeBase <T, P> node) { if (node != null) { AddTree(node.Left); RBTreeNodeBase <T, P> right = node.Right; //reuse this node to avoid superfluous dynamic memory allocation node.ClearRelations(); RBTreeNodeBase <T, P> result; bool insert = true; result = Traverse(ref insert, node.Key, node); Debug.Assert(result == node); if (!insert) { throw new System.InvalidOperationException("A node alredy exists in the destination tree."); } mCount++; AddTree(right); } }
///<summary> ///Copy from other node ///</summary> internal virtual void CopyFrom(RBTreeNodeBase <T, P> z) { if (z.mLeft != null) { z.mLeft.mParent = this; } this.mLeft = z.mLeft; if (z.mRight != null) { z.mRight.mParent = this; } this.mRight = z.mRight; //2) replace z with this in the parent node if (z.mParent != null) { if (z.mParent.mLeft == z) { z.mParent.SetLeft(this); } else { z.mParent.SetRight(this); } } this.mColor = z.mColor; this.SetParent(z.mParent); }
///<summary> ///Set parent node ///</summary> internal override void SetParent(RBTreeNodeBase <T, RBOrderedNodeParam> value) { mParent = value; if (mParent != null) { mParent.OnUpdateCount(); } }
public int IndexOfKey(T key) { RBTreeNodeBase <T, RBOrderedNodeParam> node = Find(key); if (node == null) { return(-1); } return(GetOrder(node as RBOrderedTreeNode <T>)); }
///<summary> /// Rotate our tree Right /// /// X Y /// / \ / \ /// A Y <---rb_right_rotate(Y) X C /// / \ / \ /// B C A B /// /// N.B. This does not change the ordering. /// /// We assume that neither X or Y is NULL ///<summary> protected void RightRotate(RBTreeNodeBase <T, P> y) { RBTreeNodeBase <T, P> x; // set X x = y.mLeft; // Turn X's right subtree into Y's left subtree (move B) y.mLeft = x.mRight; // If B is not null, set it's parent to be Y if (x.mRight != null) { x.mRight.mParent = y; } // Set X's parent to be what Y's parent was x.mParent = y.mParent; // if Y was the root if (y.mParent == null) { mRoot = x; } else { // Set Y's parent's left or right pointer to be X if (y == y.mParent.mLeft) { y.mParent.mLeft = x; } else { y.mParent.mRight = x; } } // Put Y on X's right x.mRight = y; // Set Y's parent to be X y.mParent = x; y.OnUpdateCount(); }
///<summary> /// Rotate our tree Left /// /// X rb_left_rotate(X)---> Y /// / \ / \ /// A Y X C /// / \ / \ /// B C A B /// /// N.B. This does not change the ordering. /// /// We assume that neither X or Y is NULL ///<summary> protected void LeftRotate(RBTreeNodeBase <T, P> x) { RBTreeNodeBase <T, P> y; // set Y y = x.mRight; // Turn Y's left subtree into X's right subtree (move B) x.mRight = y.mLeft; // If B is not null, set it's parent to be X if (y.mLeft != null) { y.mLeft.mParent = x; } // Set Y's parent to be what X's parent was y.mParent = x.mParent; // if X was the root if (x.mParent == null) { mRoot = y; } else { // Set X's parent's left or right pointer to be Y if (x == x.mParent.mLeft) { x.mParent.mLeft = y; } else { x.mParent.mRight = y; } } // Put X on Y's left y.mLeft = x; // Set X's parent to be Y x.mParent = y; x.OnUpdateCount(); }
/// <summary> /// This method was added by Dmitriano. Re-adds removed node /// with cleared relations to the tree. /// </summary> /// <param name="node">A tree node previously deleted by Remove.</param> public void Add(ITreeNode <T> node) { RBTreeNodeBase <T, P> t_node = node as RBTreeNodeBase <T, P>; t_node.CheckRelationsCleared(); bool insert = true; RBTreeNodeBase <T, P> key = Traverse(ref insert, t_node.Key, t_node); Debug.Assert(key == node); if (!insert) { throw new InvalidOperationException("Node already exists."); } mCount++; }
///<summary> ///Get order index of item ///This operation is O(logN) operation ///</summary> public int GetOrder(RBOrderedTreeNode <T> aItem) { RBTreeNodeBase <T, RBOrderedNodeParam> node = aItem; int idx = node.mParam.mRank; while (true) { if (node.mParent == null) { break; } if (node.mParent.mRight == node) { idx += node.mParent.mParam.mRank; } node = node.mParent; } return(idx - 1); }
///<summary> ///Get item by order index ///This operation is O(logN) operation ///</summary> public RBOrderedTreeNode <T> GetByOrder(int idx) { int m = idx + 1; RBTreeNodeBase <T, RBOrderedNodeParam> node = mRoot; while (node != null && m > 0) { if (m < node.mParam.mRank) { node = node.mLeft; } else if (m > node.mParam.mRank) { m = m - node.mParam.mRank; node = node.mRight; } else if (m == node.mParam.mRank) { return(node as RBOrderedTreeNode <T>); } } return(null); }
///<summary> ///Set right node ///</summary> internal override void SetRight(RBTreeNodeBase <T, RBOrderedNodeParam> value) { mRight = value; OnUpdateCount(); }
///<summary> ///Go trough tree and find the node by the key. ///Might add new node if node doesn't exist. ///node_to_reuse parameter added by Dmitriano to avoid superfluous dynamic memory allocation ///if node_to_reuse is not null aKey should be equal to node_to_reuse.Key ///</summary> internal RBTreeNodeBase <T, P> Traverse(ref bool aInsert, T aKey, RBTreeNodeBase <T, P> node_to_reuse = null) { RBTreeNodeBase <T, P> x, y, z; int cmp; //walk down the tree y = null; x = mRoot; while (x != null) { y = x; cmp = mComparer.Compare(aKey, x.mKey); if (!mUnique && cmp == 0 && aInsert == true) { cmp = 1; } if (cmp < 0) { x = x.mLeft; } else if (cmp > 0) { x = x.mRight; } else { aInsert = false; return(x); } } //x is null. return null if node must not be inserted if (!aInsert) { return(null); } if (node_to_reuse != null) //this condition was changed by Dmitriano { z = node_to_reuse; //ignore aKey parameter here } else { z = NewNode(); z.mKey = aKey; } //x is null and insert operation is requested //create new node z.mParent = y; if (y == null) { mRoot = z; } else { cmp = mComparer.Compare(z.mKey, y.mKey); if (cmp == 0) { cmp = 1; } if (cmp < 0) { y.SetLeft(z); } else { y.SetRight(z); } } z.mColor = RBTreeColor.Red; Balance(z); mRoot.mColor = RBTreeColor.Black; return(z); }
///<summary> ///Balance tree past inserting ///</summary> protected void Balance(RBTreeNodeBase <T, P> z) { RBTreeNodeBase <T, P> x, y; //Having added a red node, we must now walk back up the tree balancing //it, by a series of rotations and changing of colours x = z; //While we are not at the top and our parent node is red //N.B. Since the root node is garanteed black, then we //are also going to stop if we are the child of the root while (x != mRoot && (x.mParent.mColor == RBTreeColor.Red)) { //if our parent is on the left side of our grandparent if (x.mParent == x.mParent.mParent.mLeft) { //get the right side of our grandparent (uncle?) y = x.mParent.mParent.mRight; if (y != null && y.mColor == RBTreeColor.Red) { //make our parent black x.mParent.mColor = RBTreeColor.Black; //make our uncle black y.mColor = RBTreeColor.Black; //make our grandparent red x.mParent.mParent.mColor = RBTreeColor.Red; //now consider our grandparent x = x.mParent.mParent; } else { //if we are on the right side of our parent if (x == x.mParent.mRight) { //Move up to our parent x = x.mParent; LeftRotate(x); } /* make our parent black */ x.mParent.mColor = RBTreeColor.Black; /* make our grandparent red */ x.mParent.mParent.mColor = RBTreeColor.Red; /* right rotate our grandparent */ RightRotate(x.mParent.mParent); } } else { //everything here is the same as above, but //exchanging left for right y = x.mParent.mParent.mLeft; if (y != null && y.mColor == RBTreeColor.Red) { x.mParent.mColor = RBTreeColor.Black; y.mColor = RBTreeColor.Black; x.mParent.mParent.mColor = RBTreeColor.Red; x = x.mParent.mParent; } else { if (x == x.mParent.mLeft) { x = x.mParent; RightRotate(x); } x.mParent.mColor = RBTreeColor.Black; x.mParent.mParent.mColor = RBTreeColor.Red; LeftRotate(x.mParent.mParent); } } } mRoot.mColor = RBTreeColor.Black; }
///<summary> ///Remove all items ///</summary> public void Clear() { mRoot = null; mCount = 0; }
///<summary> ///Set parent node ///</summary> internal virtual void SetParent(RBTreeNodeBase <T, P> value) { mParent = value; }
///<summary> ///Set left node ///</summary> internal virtual void SetLeft(RBTreeNodeBase <T, P> value) { mLeft = value; }
///<summary> ///Set right node ///</summary> internal virtual void SetRight(RBTreeNodeBase <T, P> value) { mRight = value; }
///<summary> ///Copy from other node ///</summary> internal override void CopyFrom(RBTreeNodeBase <T, RBOrderedNodeParam> z) { this.mParam.mRank = z.mParam.mRank; this.mParam.mCount = z.mParam.mCount; base.CopyFrom(z); }
/// <summary> /// Delete the node z, and free up the space /// </summary> protected virtual void Delete(RBTreeNodeBase <T, P> z) { RBTreeNodeBase <T, P> x, y; if (z.mLeft == null || z.mRight == null) { y = z; } else { y = Successor(z); } if (y.mLeft != null) { x = y.mLeft; } else { x = y.mRight; } if (x != null) { x.SetParent(y.mParent); } if (y.mParent == null) { mRoot = x; } else { if (y == y.mParent.mLeft) { y.mParent.SetLeft(x); } else { y.mParent.SetRight(x); } } if (y != z) { //we must replace 'z' with 'y' node y.CopyFrom(z); if (z == mRoot) { mRoot = y; } //we do this all above instead of the following line in original code //to provide guarantee of the persistence of the node in the tree //z.mKey = y.mKey; } if (y.mColor == RBTreeColor.Black && x != null) { DeleteFix(x); } }
/// <summary> /// Restore the reb-black properties after a delete /// </summary> /// <param name="x"></param> protected void DeleteFix(RBTreeNodeBase <T, P> x) { RBTreeNodeBase <T, P> w; while (x != mRoot && x.mColor == RBTreeColor.Black) { if (x == x.mParent.mLeft) { w = x.mParent.mRight; if (w == null) { x = x.mParent; continue; } if (w.mColor == RBTreeColor.Red) { w.mColor = RBTreeColor.Black; x.mParent.mColor = RBTreeColor.Red; LeftRotate(x.mParent); w = x.mParent.mRight; } if (w == null) { x = x.mParent; continue; } if ((w.mLeft == null || w.mLeft.mColor == RBTreeColor.Black) && (w.mRight == null || w.mRight.mColor == RBTreeColor.Black)) { w.mColor = RBTreeColor.Red; x = x.mParent; } else { if (w.mRight == null || w.mRight.mColor == RBTreeColor.Black) { if (w.mLeft != null) { w.mLeft.mColor = RBTreeColor.Black; } w.mColor = RBTreeColor.Red; RightRotate(w); w = x.mParent.mRight; } w.mColor = x.mParent.mColor; x.mParent.mColor = RBTreeColor.Black; if (w.mRight != null) { w.mRight.mColor = RBTreeColor.Black; } LeftRotate(x.mParent); x = mRoot; } } else { w = x.mParent.mLeft; if (w == null) { x = x.mParent; continue; } if (w.mColor == RBTreeColor.Red) { w.mColor = RBTreeColor.Black; x.mParent.mColor = RBTreeColor.Red; RightRotate(x.mParent); w = x.mParent.mLeft; } if (w == null) { x = x.mParent; continue; } if ((w.mRight == null || w.mRight.mColor == RBTreeColor.Black) && (w.mLeft == null || w.mLeft.mColor == RBTreeColor.Black)) { w.mColor = RBTreeColor.Red; x = x.mParent; } else { if (w.mLeft == null || w.mLeft.mColor == RBTreeColor.Black) { if (w.mRight != null) { w.mRight.mColor = RBTreeColor.Black; } w.mColor = RBTreeColor.Red; LeftRotate(w); w = x.mParent.mLeft; } w.mColor = x.mParent.mColor; x.mParent.mColor = RBTreeColor.Black; if (w.mLeft != null) { w.mLeft.mColor = RBTreeColor.Black; } RightRotate(x.mParent); x = mRoot; } } } x.mColor = RBTreeColor.Black; }