//+------------------------------------------------------------------+ //| Tree.mqh | //| Copyright 2000-2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "TreeNode.mqh" //+------------------------------------------------------------------+ //| Class CTree. | //| Purpose: Building a binary tree of instances of CTreeNode class | //| and its derviatives. | //| Derives from class CTreeNode. | //+------------------------------------------------------------------+ class CTree : public CTreeNode { protected: CTreeNode *m_root_node; // root node of the tree public: CTree(void); ~CTree(void); //--- methods of access to protected data CTreeNode *Root(void) const { return(m_root_node); } //--- method of identifying the object virtual int Type() const { return(0x9999); } //--- method of filling the tree CTreeNode *Insert(CTreeNode *new_node); //--- methods of removing tree nodes bool Detach(CTreeNode *node); bool Delete(CTreeNode *node); void Clear(void); //--- method of searching data in the tree CTreeNode *Find(const CTreeNode *node); //--- method to create elements in the tree virtual CTreeNode *CreateElement() { return(NULL); } //--- methods for working with files virtual bool Save(const int file_handle); virtual bool Load(const int file_handle); protected: void Balance(CTreeNode *node); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTree::CTree(void) : m_root_node(NULL) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CTree::~CTree(void) { Clear(); } //+------------------------------------------------------------------+ //| Method of adding a node to the tree | //+------------------------------------------------------------------+ CTreeNode *CTree::Insert(CTreeNode *new_node) { CTreeNode *p_node; CTreeNode *result=m_root_node; //--- check if(!CheckPointer(new_node)) return(NULL); //--- add if(result!=NULL) { p_node=NULL; result=m_root_node; while(result!=NULL && result.Compare(new_node)!=0) { p_node=result; result=result.GetNext(new_node); } if(result!=NULL) return(result); if(p_node.Compare(new_node)>0) p_node.Left(new_node); else p_node.Right(new_node); new_node.Parent(p_node); Balance(p_node); } else m_root_node=new_node; //--- result return(result); } //+------------------------------------------------------------------+ //| Method of removing a node from the tree | //+------------------------------------------------------------------+ bool CTree::Delete(CTreeNode *node) { //--- check if(!CheckPointer(node)) return(false); //--- delete if(Detach(node) && CheckPointer(node)==POINTER_DYNAMIC) delete node; //--- successful return(true); } //+------------------------------------------------------------------+ //| Method of detaching node from the tree | //+------------------------------------------------------------------+ bool CTree::Detach(CTreeNode *node) { CTreeNode *curr_node,*tmp_node; CTreeNode *nodeA,*nodeB; //--- check curr_node=node; if(!CheckPointer(curr_node)) return(false); //--- detach if(curr_node.BalanceL()>curr_node.BalanceR()) { nodeA=curr_node.Left(); while(nodeA.Right()!=NULL) nodeA=nodeA.Right(); nodeB=nodeA.Parent(); if(nodeB!=curr_node) { nodeB.Right(nodeA.Left()); tmp_node=nodeB.Right(); if(tmp_node!=NULL) tmp_node.Parent(nodeB); tmp_node=curr_node.Left(); nodeA.Left(tmp_node); tmp_node.Parent(nodeA); } //--- left link of curr_node is already installed as it should be curr_node.Left(NULL); //--- transferring the right link of curr_node to nodeA nodeA.Right(curr_node.Right()); tmp_node=curr_node.Right(); if(tmp_node!=NULL) tmp_node.Parent(nodeA); curr_node.Right(NULL); //--- transferring the root link of curr_node to nodeA tmp_node=curr_node.Parent(); nodeA.Parent(tmp_node); if(tmp_node!=NULL) { if(tmp_node.Left()==curr_node) tmp_node.Left(nodeA); else tmp_node.Right(nodeA); } else { curr_node.Parent(NULL); m_root_node=nodeA; tmp_node=nodeA; } Balance(tmp_node); } else { if(curr_node.BalanceR()>0) { nodeA=curr_node.Right(); while(nodeA.Left()!=NULL) nodeA=nodeA.Left(); nodeB=nodeA.Parent(); if(nodeB!=curr_node) { nodeB.Left(nodeA.Right()); tmp_node=nodeB.Left(); if(tmp_node!=NULL) tmp_node.Parent(nodeB); tmp_node=curr_node.Right(); nodeA.Right(tmp_node); tmp_node.Parent(nodeA); } //--- right link of curr_node is already installed as it should be curr_node.Right(NULL); //--- transferring the left link of curr_node to nodeA nodeA.Left(curr_node.Left()); tmp_node=curr_node.Left(); if(tmp_node!=NULL) tmp_node.Parent(nodeA); curr_node.Left(NULL); //--- transferring the root link of curr_node to nodeA tmp_node=curr_node.Parent(); nodeA.Parent(tmp_node); if(tmp_node!=NULL) { if(tmp_node.Left()==curr_node) tmp_node.Left(nodeA); else tmp_node.Right(nodeA); } else { curr_node.Parent(NULL); m_root_node=nodeA; tmp_node=nodeA; } Balance(tmp_node); } else { //--- node list if(curr_node.Parent()==NULL) m_root_node=NULL; else { tmp_node=curr_node.Parent(); if(tmp_node.Left()==curr_node) tmp_node.Left(NULL); else tmp_node.Right(NULL); curr_node.Parent(NULL); } Balance(curr_node.Parent()); } } //--- successful return(true); } //+------------------------------------------------------------------+ //| Method of cleaning the tree | //+------------------------------------------------------------------+ void CTree::Clear(void) { if(CheckPointer(m_root_node)==POINTER_DYNAMIC) delete m_root_node; m_root_node=NULL; } //+------------------------------------------------------------------+ //| Method of searching for a node in the tree | //+------------------------------------------------------------------+ CTreeNode *CTree::Find(const CTreeNode *node) { CTreeNode *result=m_root_node; //--- find while(result!=NULL && result.Compare(node)!=0) result=result.GetNext(node); //--- result return(result); } //+------------------------------------------------------------------+ //| Method of balancing the tree | //+------------------------------------------------------------------+ void CTree::Balance(CTreeNode *node) { CTreeNode *nodeA,*nodeB,*nodeC,*curr_node,*tmp_node; //--- curr_node=node; while(curr_node!=NULL) { curr_node.RefreshBalance(); if(MathAbs(curr_node.BalanceL()-curr_node.BalanceR())<=1) curr_node=curr_node.Parent(); else { if(curr_node.BalanceR()>curr_node.BalanceL()) { //--- rotation to the right tmp_node=curr_node.Right(); if(tmp_node.BalanceL()>tmp_node.BalanceR()) { //--- great rotation to the right nodeA=curr_node; nodeB=nodeA.Right(); nodeC=nodeB.Left(); nodeC.Parent(nodeA.Parent()); tmp_node=nodeC.Parent(); if(tmp_node!=NULL) { if(tmp_node.Right()==nodeA) tmp_node.Right(nodeC); else tmp_node.Left(nodeC); } else m_root_node=nodeC; nodeA.Parent(nodeC); nodeB.Parent(nodeC); nodeA.Right(nodeC.Left()); tmp_node=nodeA.Right(); if(tmp_node!=NULL) tmp_node.Parent(nodeA); nodeC.Left(nodeA); nodeB.Left(nodeC.Right()); tmp_node=nodeB.Left(); if(tmp_node!=NULL) tmp_node.Parent(nodeB); nodeC.Right(nodeB); if(m_root_node==nodeA) m_root_node=nodeC; curr_node=nodeC.Parent(); } else { //--- slight rotation to the right nodeA=curr_node; nodeB=nodeA.Right(); nodeB.Parent(nodeA.Parent()); tmp_node=nodeB.Parent(); if(tmp_node!=NULL) { if(tmp_node.Right()==nodeA) tmp_node.Right(nodeB); else tmp_node.Left(nodeB); } else m_root_node=nodeB; nodeA.Parent(nodeB); nodeA.Right(nodeB.Left()); tmp_node=nodeA.Right(); if(tmp_node!=NULL) tmp_node.Parent(nodeA); nodeB.Left(nodeA); if(m_root_node==nodeA) m_root_node=nodeB; curr_node=nodeB.Parent(); } } else { //--- rotation to the left tmp_node=curr_node.Left(); if(tmp_node.BalanceR()>tmp_node.BalanceL()) { //--- great rotation to the left nodeA=curr_node; nodeB=nodeA.Left(); nodeC=nodeB.Right(); nodeC.Parent(nodeA.Parent()); tmp_node=nodeC.Parent(); if(tmp_node!=NULL) { if(tmp_node.Right()==nodeA) tmp_node.Right(nodeC); else tmp_node.Left(nodeC); } else m_root_node=nodeC; nodeA.Parent(nodeC); nodeB.Parent(nodeC); nodeA.Left(nodeC.Right()); tmp_node=nodeA.Left(); if(tmp_node!=NULL) tmp_node.Parent(nodeA); nodeC.Right(nodeA); nodeB.Right(nodeC.Left()); tmp_node=nodeB.Right(); if(tmp_node!=NULL) tmp_node.Parent(nodeB); nodeC.Left(nodeB); if(m_root_node==nodeA) m_root_node=nodeC; curr_node=nodeC.Parent(); } else { //--- small rotation to the left nodeA=curr_node; nodeB=nodeA.Left(); nodeB.Parent(nodeA.Parent()); tmp_node=nodeB.Parent(); if(tmp_node!=NULL) { if(tmp_node.Right()==nodeA) tmp_node.Right(nodeB); else tmp_node.Left(nodeB); } else m_root_node=nodeB; nodeA.Parent(nodeB); nodeA.Left(nodeB.Right()); tmp_node=nodeA.Left(); if(tmp_node!=NULL) tmp_node.Parent(nodeA); nodeB.Right(nodeA); if(m_root_node==nodeA) m_root_node=nodeB; curr_node=nodeB.Parent(); } } } } } //+------------------------------------------------------------------+ //| Writing tree to file | //+------------------------------------------------------------------+ bool CTree::Save(const int file_handle) { //--- check if(file_handle==INVALID_HANDLE) return(false); if(m_root_node==NULL) return(true); //--- result return(m_root_node.SaveNode(file_handle)); } //+------------------------------------------------------------------+ //| Reading tree from file | //+------------------------------------------------------------------+ bool CTree::Load(const int file_handle) { //--- check if(file_handle==INVALID_HANDLE) return(false); //--- create root node only Clear(); Insert(CreateElement()); //--- result return(m_root_node.LoadNode(file_handle,m_root_node)); } //+------------------------------------------------------------------+