//+------------------------------------------------------------------+ //| RedBlackTree.mqh | //| Copyright 2000-2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include #include #include #include #include "Stack.mqh" //+------------------------------------------------------------------+ //| Enum ENUM_RED_BLACK_TREE_NODE_TYPE. | //| Usage: Defines possible node colors for red black tree. | //+------------------------------------------------------------------+ enum ENUM_RED_BLACK_TREE_NODE_TYPE { RED_BLACK_TREE_NODE_RED=0, RED_BLACK_TREE_NODE_BLACK=1 }; //+------------------------------------------------------------------+ //| Class CRedBlackTreeNode. | //| Usage: Represents a node of red black tree. | //+------------------------------------------------------------------+ template class CRedBlackTreeNode { private: T m_value; CRedBlackTreeNode*m_left; CRedBlackTreeNode*m_right; CRedBlackTreeNode*m_parent; ENUM_RED_BLACK_TREE_NODE_TYPE m_clr; public: CRedBlackTreeNode(void); CRedBlackTreeNode(T value); ~CRedBlackTreeNode(void); //--- methods of access to protected data T Value(void) { return(m_value); } void Value(T value) { m_value=value; } CRedBlackTreeNode *Parent(void) { return(m_parent); } void Parent(CRedBlackTreeNode*node) { m_parent=node; } CRedBlackTreeNode *Left(void) { return(m_left); } void Left(CRedBlackTreeNode*node) { m_left=node; } CRedBlackTreeNode *Right(void) { return(m_right); } void Right(CRedBlackTreeNode*node) { m_right=node; } ENUM_RED_BLACK_TREE_NODE_TYPE Color(void) { return(m_clr); } void Color(ENUM_RED_BLACK_TREE_NODE_TYPE clr) { m_clr=clr; } //--- check node is empty bool IsLeaf(void); //--- create new empty node static CRedBlackTreeNode*CreateEmptyNode(void); }; //+------------------------------------------------------------------+ //| Initializes a new instance of the CRedBlackTreeNode class that| //| is empty. | //+------------------------------------------------------------------+ template CRedBlackTreeNode::CRedBlackTreeNode(void) : m_clr(RED_BLACK_TREE_NODE_RED) { } //+------------------------------------------------------------------+ //| Initializes a new instance of the CRedBlackTreeNode class with| //| specified value. | //+------------------------------------------------------------------+ template CRedBlackTreeNode::CRedBlackTreeNode(T value) { m_value=value; m_clr=RED_BLACK_TREE_NODE_RED; m_left=CreateEmptyNode(); m_right=CreateEmptyNode(); } //+------------------------------------------------------------------+ //| Destructor. | //+------------------------------------------------------------------+ template CRedBlackTreeNode::~CRedBlackTreeNode(void) { if(CheckPointer(m_left)==POINTER_DYNAMIC) delete m_left; if(CheckPointer(m_right)==POINTER_DYNAMIC) delete m_right; } //+------------------------------------------------------------------+ //| Check node is empty. | //+------------------------------------------------------------------+ template bool CRedBlackTreeNode::IsLeaf(void) { return(m_clr==RED_BLACK_TREE_NODE_BLACK && CheckPointer(m_left)==POINTER_INVALID && CheckPointer(m_right)==POINTER_INVALID); } //+------------------------------------------------------------------+ //| Create new empty black node. | //+------------------------------------------------------------------+ template CRedBlackTreeNode*CRedBlackTreeNode::CreateEmptyNode(void) { CRedBlackTreeNode*new_node=new CRedBlackTreeNode(); new_node.m_clr=RED_BLACK_TREE_NODE_BLACK; new_node.m_parent=NULL; new_node.m_left=NULL; new_node.m_right=NULL; //--- return new empty node return(new_node); } //+------------------------------------------------------------------+ //| Class CRedBlackTree. | //| Usage: A red–black tree is a data structure which is a type of | //| self-balancing binary search tree. | //+------------------------------------------------------------------+ template class CRedBlackTree: public ICollection { protected: CRedBlackTreeNode*m_root_node; CRedBlackTreeNode*m_last_node; IComparer*m_comparer; int m_count; bool m_delete_comparer; public: CRedBlackTree(void); CRedBlackTree(IComparer*comparer); CRedBlackTree(ICollection*collection); CRedBlackTree(ICollection*collection,IComparer*comparer); CRedBlackTree(T &array[]); CRedBlackTree(T &array[],IComparer*comparer); ~CRedBlackTree(void); //--- methods of filling data bool Add(T value); //--- methods of access to protected data CRedBlackTreeNode*Root(void) { return(m_root_node); } int Count(void) { return(m_count); } bool Contains(T item); IComparer *Comparer(void) const { return(m_comparer); } bool TryGetMin(T &min); bool TryGetMax(T &max); //--- methods of copy data from collection int CopyTo(T &dst_array[],const int dst_start=0); //--- methods of cleaning and removing void Clear(void); bool Remove(T value); bool Remove(CRedBlackTreeNode*node); bool RemoveMin(void); bool RemoveMax(void); //--- method for searching CRedBlackTreeNode*Find(T value); CRedBlackTreeNode*FindMax(void); CRedBlackTreeNode*FindMin(void); private: void RotateRight(CRedBlackTreeNode*rotate_node); void RotateLeft(CRedBlackTreeNode*rotate_node); void BalanceTreeAfterInsert(CRedBlackTreeNode*insert_node); void BalanceTreeAfterDelete(CRedBlackTreeNode*linked_node); static void WalkNextLevel(CRedBlackTreeNode*node,T &array[],int &index); }; //+------------------------------------------------------------------+ //| Initializes a new instance of the CRedBlackTree class that is | //| empty and uses the specified comparer. | //+------------------------------------------------------------------+ template CRedBlackTree::CRedBlackTree(void): m_count(0) { //--- use default comaprer m_comparer=new CDefaultComparer(); m_delete_comparer=true; } //+------------------------------------------------------------------+ //| Initializes a new instance of the CRedBlackTree class that is | //| empty and uses the specified comparer. | //+------------------------------------------------------------------+ template CRedBlackTree::CRedBlackTree(IComparer*comparer): m_count(0) { //--- check comaprer if(CheckPointer(comparer)==POINTER_INVALID) { //--- use default comaprer m_comparer=new CDefaultComparer(); m_delete_comparer=true; } else { //--- use specified equality comaprer m_comparer=comparer; m_delete_comparer=false; } } //+------------------------------------------------------------------+ //| Initializes a new instance of the CRedBlackTree class that | //| uses the default equality comparer, contains elements copied from| //| the specified collection. | //+------------------------------------------------------------------+ template CRedBlackTree::CRedBlackTree(ICollection*collection): m_count(0) { //--- use default comaprer m_comparer=new CDefaultComparer(); m_delete_comparer=true; //--- check collection if(CheckPointer(collection)==POINTER_INVALID) return; //--- copy all elements from specified collection to array T array[]; int size=collection.CopyTo(array); //--- fill red black tree by elements from the array for(int i=0; i class that | //| uses the specified comparer and contains elements copied from | //| the specified collection. | //+------------------------------------------------------------------+ template CRedBlackTree::CRedBlackTree(ICollection*collection,IComparer*comparer): m_count(0) { //--- check comaprer if(CheckPointer(comparer)==POINTER_INVALID) { //--- use default comaprer m_comparer=new CDefaultComparer(); m_delete_comparer=true; } else { //--- use specified equality comaprer m_comparer=comparer; m_delete_comparer=false; } //--- check collection if(CheckPointer(collection)==POINTER_INVALID) return; //--- copy all elements from specified collection to array T array[]; int size=collection.CopyTo(array); //--- fill red black tree by elements from the array for(int i=0; i class that | //| uses the default equality comparer and contains elements copied | //| from the specified array. | //+------------------------------------------------------------------+ template CRedBlackTree::CRedBlackTree(T &array[]): m_count(0) { //--- use default comaprer m_comparer=new CDefaultComparer(); m_delete_comparer=true; //--- fill red black tree by elements from the specified array for(int i=0; i class that | //| uses the specified comparer and contains elements copied from | //| the specified array. | //+------------------------------------------------------------------+ template CRedBlackTree::CRedBlackTree(T &array[],IComparer*comparer): m_count(0) { //--- check comaprer if(CheckPointer(comparer)==POINTER_INVALID) { //--- use default comaprer m_comparer=new CDefaultComparer(); m_delete_comparer=true; } else { //--- use specified equality comaprer m_comparer=comparer; m_delete_comparer=false; } //--- fill red black tree by elements from the specified array for(int i=0; i CRedBlackTree::~CRedBlackTree(void) { //--- delete comparer if(m_delete_comparer) delete m_comparer; //--- clear tree Clear(); } //+------------------------------------------------------------------+ //| Adds a new item to the tree. If the element already belongs to | //| this tree, no new element will be added. | //+------------------------------------------------------------------+ template bool CRedBlackTree::Add(T value) { //--- traverse tree - find node below if(CheckPointer(Find(value))!=POINTER_INVALID) return(false); //--- create new node CRedBlackTreeNode*new_node=new CRedBlackTreeNode(value); CRedBlackTreeNode*work_node=m_root_node; while(CheckPointer(work_node)!=POINTER_INVALID && !work_node.IsLeaf()) { //--- find parent new_node.Parent(work_node); int result= m_comparer.Compare(value, work_node.Value()); if(result == 0) { //--- node with same value already exists return(false); } work_node=(result>0 ? work_node.Right() : work_node.Left()); } //--- insert node into tree starting at parent's location if(CheckPointer(new_node.Parent())!=POINTER_INVALID) { if(m_comparer.Compare(new_node.Value(),new_node.Parent().Value())>0) { if(CheckPointer(new_node.Parent().Right())==POINTER_DYNAMIC && new_node.Parent().Right().IsLeaf()) delete new_node.Parent().Right(); new_node.Parent().Right(new_node); } else { if(CheckPointer(new_node.Parent().Left())==POINTER_DYNAMIC && new_node.Parent().Left().IsLeaf()) delete new_node.Parent().Left(); new_node.Parent().Left(new_node); } } else { //--- first node added m_root_node=new_node; } //--- restore red-black properties BalanceTreeAfterInsert(new_node); m_last_node=new_node; //--- increment count m_count++; return(true); } //+------------------------------------------------------------------+ //| Determines whether this tree contains the specified item. | //+------------------------------------------------------------------+ template bool CRedBlackTree::Contains(T item) { CRedBlackTreeNode*tree_node=Find(item); return(CheckPointer(tree_node)!=POINTER_INVALID); } //+------------------------------------------------------------------+ //| Finds the minimum element stored in the tree. | //+------------------------------------------------------------------+ template bool CRedBlackTree::TryGetMin(T &min) { CRedBlackTreeNode*work_node=m_root_node; //--- check tree is empty if(CheckPointer(work_node)==POINTER_INVALID || work_node.IsLeaf()) return(false); //--- traverse to the extreme left to find the smallest key while(!work_node.Left().IsLeaf()) work_node=work_node.Left(); //--- store min value m_last_node=work_node; min=work_node.Value(); return(true); } //+------------------------------------------------------------------+ //| Finds the maximum element stored in the tree. | //+------------------------------------------------------------------+ template bool CRedBlackTree::TryGetMax(T &max) { CRedBlackTreeNode*work_node=m_root_node; //--- check tree is empty if(CheckPointer(work_node)==POINTER_INVALID || work_node.IsLeaf()) return(false); //--- traverse to the extreme right to find the largest key while(!work_node.Right().IsLeaf()) work_node=work_node.Right(); //--- store max value m_last_node=work_node; max=work_node.Value(); return(true); } //+------------------------------------------------------------------+ //| Copies a range of elements from the tree to a compatible | //| one-dimensional array. | //+------------------------------------------------------------------+ template int CRedBlackTree::CopyTo(T &dst_array[],const int dst_start=0) { //--- check root node if(CheckPointer(m_root_node)==POINTER_INVALID) return(0); //--- resize array if(dst_start+m_count>ArraySize(dst_array)) ArrayResize(dst_array,dst_start+m_count); //--- start copy int index=dst_start; if(!m_root_node.IsLeaf()) { //--- store all values in the stack WalkNextLevel(m_root_node,dst_array,index); //--- copy values from stack to array return(index-dst_start); } else { //--- tree is empty return(0); } } //+------------------------------------------------------------------+ //| Removes all nodes from the tree. | //+------------------------------------------------------------------+ template void CRedBlackTree::Clear(void) { //--- check count if(m_count>0) { //--- delete root node if(CheckPointer(m_root_node)==POINTER_DYNAMIC) delete m_root_node; //--- delete last node if(CheckPointer(m_last_node)==POINTER_DYNAMIC) delete m_last_node; m_count=0; } } //+------------------------------------------------------------------+ //| Removes a node with specified value from the tree. | //+------------------------------------------------------------------+ template bool CRedBlackTree::Remove(T value) { //--- try to find node with specified value CRedBlackTreeNode*delete_node=Find(value); if(CheckPointer(delete_node)!=POINTER_INVALID) return Remove(delete_node); return(false); } //+------------------------------------------------------------------+ //| Removes a node from the tree. | //| 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. | //+------------------------------------------------------------------+ template bool CRedBlackTree::Remove(CRedBlackTreeNode*delete_node) { //--- check node if(CheckPointer(delete_node)==POINTER_INVALID) return(false); //--- check delete node conatins in tree bool contains=false; //--- walk of a tree and try to find the delete node CRedBlackTreeNode*tree_node=m_root_node; while(CheckPointer(tree_node)!=POINTER_INVALID && !tree_node.IsLeaf()) { //--- check specified node is delete node if(tree_node==delete_node) { contains=true; break; } else { //--- determine qual between specified node and delete node int result=m_comparer.Compare(delete_node.Value(),tree_node.Value()); if(result>0) tree_node=tree_node.Right(); // walk of a right tree else if(result<0) tree_node=tree_node.Left(); // walk of a left tree else break; // values of nodes are equal, but delete node does not belong to this tree } } //--- check delete node not belong to this tree if(!contains) return(false); //--- work node CRedBlackTreeNode*work_node; //--- find the replacement node - the node one with at *most* one child. if(delete_node.Left().IsLeaf() || delete_node.Right().IsLeaf()) { work_node=delete_node; } else { //--- traverse right subtree work_node=delete_node.Right(); //--- to find next node in sequence while(!work_node.Left().IsLeaf()) work_node=work_node.Left(); } //--- at this point, work_node contains the replacement node. it's content will be copied to the valules in the node to be deleted //--- linked_node is the node that will be linked to work_node's old parent. CRedBlackTreeNode*linked_node=(work_node.Left().IsLeaf() ? work_node.Right() : work_node.Left()); //--- replace linked_node's parent with work_node's parent and //--- link linked_node to proper subtree in parent //--- this removes work_node from the chain linked_node.Parent(work_node.Parent()); if(CheckPointer(work_node.Parent())!=POINTER_INVALID) { if(work_node==work_node.Parent().Left()) work_node.Parent().Left(linked_node); else work_node.Parent().Right(linked_node); } else { //--- make linked_node the root node m_root_node=linked_node; } //--- copy the values from work_node (the replacement node) to the node being deleted. if(work_node!=delete_node) delete_node.Value(work_node.Value()); //--- restore red-black properties if(work_node.Color()==RED_BLACK_TREE_NODE_BLACK) BalanceTreeAfterDelete(linked_node); //--- delete node if(m_count>1) { if(linked_node==work_node.Left()) work_node.Left(NULL); else work_node.Right(NULL); } delete work_node; //--- decrement count m_count--; return(true); } //+------------------------------------------------------------------+ //| Removes a node with minimum value from the tree. | //+------------------------------------------------------------------+ template bool CRedBlackTree::RemoveMin(void) { //--- check root node if(CheckPointer(m_root_node)==POINTER_INVALID) return(false); //--- find and remove node with minimum value return Remove(FindMin()); } //+------------------------------------------------------------------+ //| Removes a node with maximum value from the tree. | //+------------------------------------------------------------------+ template bool CRedBlackTree::RemoveMax(void) { //--- check root node if(CheckPointer(m_root_node)==POINTER_INVALID) return(false); //--- find and remove node with maximum value return Remove(FindMax()); } //+------------------------------------------------------------------+ //| Attempts to find a node that contains the specified value. | //+------------------------------------------------------------------+ template CRedBlackTreeNode*CRedBlackTree::Find(T value) { int result; //--- check last node if(CheckPointer(m_last_node)!=POINTER_INVALID && !m_last_node.IsLeaf()) { result=m_comparer.Compare(value,m_last_node.Value()); if(result==0) return(m_last_node); } //--- begin at root CRedBlackTreeNode*tree_node=m_root_node; //--- traverse tree until node is found while(CheckPointer(tree_node)!=POINTER_INVALID && !tree_node.IsLeaf()) { result=m_comparer.Compare(value,tree_node.Value()); if(result==0) { m_last_node=tree_node; return(tree_node); } tree_node=(result<0 ? tree_node.Left() : tree_node.Right()); } return(NULL); } //+------------------------------------------------------------------+ //| Attempts to find a node that contains the minimum value. | //+------------------------------------------------------------------+ template CRedBlackTreeNode*CRedBlackTree::FindMin(void) { CRedBlackTreeNode*work_node=m_root_node; //--- check tree is empty if(CheckPointer(work_node)==POINTER_INVALID || work_node.IsLeaf()) return(NULL); //--- traverse to the extreme left to find the smallest key while(!work_node.Left().IsLeaf()) work_node=work_node.Left(); //--- store min value m_last_node=work_node; return(work_node); } //+------------------------------------------------------------------+ //| Attempts to find a node that contains the maximum value. | //+------------------------------------------------------------------+ template CRedBlackTreeNode*CRedBlackTree::FindMax(void) { CRedBlackTreeNode*work_node=m_root_node; //--- check tree is empty if(CheckPointer(work_node)==POINTER_INVALID || work_node.IsLeaf()) return(NULL); //--- traverse to the extreme right to find the largest key while(!work_node.Right().IsLeaf()) work_node=work_node.Right(); //--- store max value m_last_node=work_node; return(work_node); } //+------------------------------------------------------------------+ //| Pushing node rotate_node down and to the right to balance the | //| tree. rotate_node's Left child (work_node) replaces rotate_node | //| (since rotate_node < work_node), and work_node's Right child | //| becomes rotate_node's Left child (since it's < rotate_node but > | //| work_node). | //+------------------------------------------------------------------+ template void CRedBlackTree::RotateRight(CRedBlackTreeNode*rotate_node) { //--- get rotate_node's Left node, this becomes work_node CRedBlackTreeNode*work_node=rotate_node.Left(); //--- set rotate_node's Right link //--- work_node's Right child becomes rotate_node's Left child rotate_node.Left(work_node.Right()); //--- modify parents if(!work_node.Right().IsLeaf()) { //--- sets work_node's Right Parent to rotate_node work_node.Right().Parent(rotate_node); } if(!work_node.IsLeaf()) { //--- set work_node's Parent to rotate_node's Parent work_node.Parent(rotate_node.Parent()); } if(CheckPointer(rotate_node.Parent())!=POINTER_INVALID) { //--- determine which side of it's Parent rotate_node was on if(rotate_node==rotate_node.Parent().Right()) { //--- set Right Parent to work_node rotate_node.Parent().Right(work_node); } else { //--- set Left Parent to work_node rotate_node.Parent().Left(work_node); } } else { m_root_node=work_node; } //--- link rotate_node and work_node //--- put rotate_node on work_node's Right work_node.Right(rotate_node); //--- set work_node as rotate_node's Parent if(!rotate_node.IsLeaf()) rotate_node.Parent(work_node); } //+------------------------------------------------------------------+ //| Pushing node rotate_node down and to the Left to balance the | //| tree. rotate_node's Right child (work_node) replaces rotate_node | //| (since work_node > rotate_node), and work_node's Left child | //| becomes rotate_node's Right child (since it's < work_node but > | //| rotate_node). | //+------------------------------------------------------------------+ template void CRedBlackTree::RotateLeft(CRedBlackTreeNode*rotate_node) { //--- get rotate_node's Right node, this becomes work_node CRedBlackTreeNode*work_node=rotate_node.Right(); //--- set rotate_node's Right link //--- work_node's Left child's becomes rotate_node's Right child rotate_node.Right(work_node.Left()); //--- modify parents if(!work_node.Left().IsLeaf()) { //--- sets work_node's Left Parent to rotate_node work_node.Left().Parent(rotate_node); } if(!work_node.IsLeaf()) { //--- set work_node's Parent to rotate_node's Parent work_node.Parent(rotate_node.Parent()); } if(CheckPointer(rotate_node.Parent())!=POINTER_INVALID) { //--- determine which side of it's Parent rotate_node was on if(rotate_node==rotate_node.Parent().Left()) { //--- set Left Parent to work_node rotate_node.Parent().Left(work_node); } else { //--- set Right Parent to work_node rotate_node.Parent().Right(work_node); } } else { m_root_node=work_node; } //--- link rotate_node and work_node //--- put rotate_node on work_node's Left work_node.Left(rotate_node); //--- set work_node as rotate_node's Parent if(!rotate_node.IsLeaf()) rotate_node.Parent(work_node); } //+------------------------------------------------------------------+ //| Additions to red-black trees usually destroy the red-black | //| properties. Examine the tree and restore. Rotations are normally | //| required to restore it. | //+------------------------------------------------------------------+ template void CRedBlackTree::BalanceTreeAfterInsert(CRedBlackTreeNode*insert_node) { //--- maintain red-black tree properties after adding new node while(insert_node!=m_root_node && insert_node.Parent().Color()==RED_BLACK_TREE_NODE_RED) { //--- parent node is colored red CRedBlackTreeNode*work_node; //--- determine traversal path if(insert_node.Parent()==insert_node.Parent().Parent().Left()) { //--- get rigth uncle work_node=insert_node.Parent().Parent().Right(); if(CheckPointer(work_node)!=POINTER_INVALID && work_node.Color()==RED_BLACK_TREE_NODE_RED) { //--- uncle is red //--- change parent and uncle to black insert_node.Parent().Color(RED_BLACK_TREE_NODE_BLACK); work_node.Color(RED_BLACK_TREE_NODE_BLACK); //--- grandparent must be red insert_node.Parent().Parent().Color(RED_BLACK_TREE_NODE_RED); //--- continue loop with grandparent insert_node=insert_node.Parent().Parent(); } else { //--- uncle is black //--- determine if new node is greater than parent if(insert_node==insert_node.Parent().Right()) { //--- new node is greater than parent insert_node=insert_node.Parent(); RotateLeft(insert_node); } //--- new node is less than parent insert_node.Parent().Color(RED_BLACK_TREE_NODE_BLACK); insert_node.Parent().Parent().Color(RED_BLACK_TREE_NODE_RED); RotateRight(insert_node.Parent().Parent()); } } else { //--- get left uncle work_node=insert_node.Parent().Parent().Left(); if(CheckPointer(work_node)!=POINTER_INVALID && work_node.Color()==RED_BLACK_TREE_NODE_RED) { //--- uncle is red //--- change parent and uncle to black insert_node.Parent().Color(RED_BLACK_TREE_NODE_BLACK); work_node.Color(RED_BLACK_TREE_NODE_BLACK); //--- grandparent must be red insert_node.Parent().Parent().Color(RED_BLACK_TREE_NODE_RED); //--- continue loop with grandparent insert_node=insert_node.Parent().Parent(); } else { //--- uncle is black //--- determine if new node is greater than parent if(insert_node==insert_node.Parent().Left()) { //--- new node is greater than parent insert_node=insert_node.Parent(); RotateRight(insert_node); } //--- new node is less than parent insert_node.Parent().Color(RED_BLACK_TREE_NODE_BLACK); insert_node.Parent().Parent().Color(RED_BLACK_TREE_NODE_RED); RotateLeft(insert_node.Parent().Parent()); } } } //--- root should always be black m_root_node.Color(RED_BLACK_TREE_NODE_BLACK); } //+------------------------------------------------------------------+ //| Deletions from red-black trees may destroy the red-black | //| properties. Examine the tree and restore. Rotations are normally | //| required to restore it. | //+------------------------------------------------------------------+ template void CRedBlackTree::BalanceTreeAfterDelete(CRedBlackTreeNode*linked_node) { //--- maintain Red-Black tree balance after deleting node while(linked_node!=m_root_node && linked_node.Color()==RED_BLACK_TREE_NODE_BLACK) { CRedBlackTreeNode*work_node; //--- determine traversal path if(linked_node==linked_node.Parent().Left()) { //--- work node is delete node sibling work_node=linked_node.Parent().Right(); if(work_node.Color()==RED_BLACK_TREE_NODE_RED) { //--- delete node is black, work node is red - make both black and rotate linked_node.Parent().Color(RED_BLACK_TREE_NODE_RED); work_node.Color(RED_BLACK_TREE_NODE_BLACK); RotateLeft(linked_node.Parent()); work_node=linked_node.Parent().Right(); } //--- check work node is not leaf if(work_node.IsLeaf()) return; if(work_node.Left().Color()==RED_BLACK_TREE_NODE_BLACK && work_node.Right().Color()==RED_BLACK_TREE_NODE_BLACK) { //--- children are both black //--- change parent to red work_node.Color(RED_BLACK_TREE_NODE_RED); //--- move up the tree linked_node=linked_node.Parent(); } else { if(work_node.Right().Color()==RED_BLACK_TREE_NODE_BLACK) { work_node.Left().Color(RED_BLACK_TREE_NODE_BLACK); work_node.Color(RED_BLACK_TREE_NODE_RED); RotateRight(work_node); work_node=linked_node.Parent().Right(); } work_node.Color(linked_node.Parent().Color()); linked_node.Parent().Color(RED_BLACK_TREE_NODE_BLACK); work_node.Right().Color(RED_BLACK_TREE_NODE_BLACK); RotateLeft(linked_node.Parent()); linked_node=m_root_node; } } else { //--- work node is delete node sibling work_node=linked_node.Parent().Left(); if(work_node.Color()==RED_BLACK_TREE_NODE_RED) { //--- delete node is black, work node is red - make both black and rotate linked_node.Parent().Color(RED_BLACK_TREE_NODE_RED); work_node.Color(RED_BLACK_TREE_NODE_BLACK); RotateRight(linked_node.Parent()); work_node=linked_node.Parent().Left(); } //--- check work node is not leaf if(work_node.IsLeaf()) return; if(work_node.Right().Color()==RED_BLACK_TREE_NODE_BLACK && work_node.Left().Color()==RED_BLACK_TREE_NODE_BLACK) { //--- children are both black //--- change parent to red work_node.Color(RED_BLACK_TREE_NODE_RED); //--- move up the tree linked_node=linked_node.Parent(); } else { if(work_node.Left().Color()==RED_BLACK_TREE_NODE_BLACK) { work_node.Right().Color(RED_BLACK_TREE_NODE_BLACK); work_node.Color(RED_BLACK_TREE_NODE_RED); RotateLeft(work_node); work_node=linked_node.Parent().Left(); } work_node.Color(linked_node.Parent().Color()); linked_node.Parent().Color(RED_BLACK_TREE_NODE_BLACK); work_node.Left().Color(RED_BLACK_TREE_NODE_BLACK); RotateRight(linked_node.Parent()); linked_node=m_root_node; } } } linked_node.Color(RED_BLACK_TREE_NODE_BLACK); } //+------------------------------------------------------------------+ //| Recursive walk of a tree. | //+------------------------------------------------------------------+ template void CRedBlackTree::WalkNextLevel(CRedBlackTreeNode*node,T &array[],int &index) { //--- walk of a left subtree if(!node.Left().IsLeaf()) WalkNextLevel(node.Left(),array,index); //--- chech index if(index>=ArraySize(array)) return; //--- store value in the array array[index++]=node.Value(); //--- walk of a right subtree if(!node.Right().IsLeaf()) WalkNextLevel(node.Right(),array,index); } //+------------------------------------------------------------------+