CTree

Класс CTree является классом двоичного дерева экземпляров класса CTreeNode и его наследников.

Описание

Класс CTree обеспечивает возможность работы с двоичным деревом экземпляров класса CTreeNode и его наследников. В классе реализованы возможности добавления/вставки/удаления элементов дерева, поиска в дереве. Кроме того, реализованы методы работы с файлом.

Следует отметить что, в классе CTree не реализован механизм управления динамической памятью (в отличии от классов CList и CArrayObj). Все узлы дерева удаляются с освобождением памяти.

Декларация

   class CTree : public CTreeNode

Заголовок

   #include <Arrays\Tree.mqh>

Иерархия наследования

  CObject

      CTreeNode

          CTree

Методы класса по группам

Атрибуты

 

Root

Получает корневой узел дерева

Создание нового элемента

 

virtual CreateElement

Создает новый экземпляр узла

Наполнение

 

Insert

Добавляет узел в дерево

Удаление

 

Detach

Изымает указанный узел из дерева

Delete

Удаляет указанный узел из дерева

Clear

Удаляет все узлы дерева

Поиск

 

Find

Ищет в дереве узел по образцу

Ввод/вывод

 

virtual Save

Сохраняет данные дерева в файл

virtual Load

Загружает данные дерева из файла

virtual Type

Получает идентификатор типа дерева

Методы унаследованные от CObject

Prev, Prev, Next, Next, Compare

Методы унаследованные от CTreeNode

Parent, Parent, Left, Left, Right, Right, Balance, BalanceL, BalanceR, RefreshBalance, GetNext, SaveNode, LoadNode

Практическое применение имеют деревья потомков класса CTreeNode – потомки класса CTree.

Потомок класса CTree должен иметь переопределенный метод CreateElement, создающий новый экземпляр класса-потомка CTreeNode.

Рассмотрим пример класса-потомка CTree.

//+------------------------------------------------------------------+
//|                                                       MyTree.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                       https://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//---
#include <Arrays\Tree.mqh>
#include "MyTreeNode.mqh"
//---
input int extCountedNodes = 100;
//+------------------------------------------------------------------+
//| Описываем класс CMyTree производный от CTree.                    |
//+------------------------------------------------------------------+
//| Класс CMyTree.                                                   |
//| Назначение: Построение и навигация двоичного дерева поиска.      |
//+------------------------------------------------------------------+
class CMyTree : public CTree
  {
public:
   //--- методы поиска в дереве по данным пользователя
   CMyTreeNode*        FindByLong(long find_long);
   //--- метод создания элемента дерева
   virtual CTreeNode *CreateElement();
  };
//---
CMyTree MyTree;
//+------------------------------------------------------------------+
//| Создание нового узла дерева.                                     |
//| INPUT:  нет.                                                     |
//| OUTPUT: указатель на новый узел дерева если ОК, либо NULL.       |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
CTreeNode *CMyTree::CreateElement()
  {
   CMyTreeNode *node=new CMyTreeNode;
//---
   return(node);
  }
//+------------------------------------------------------------------+
//| Поиск элемента в списке по значению m_long.                      |
//| INPUT:  find_long - искомое значение.                            |
//| OUTPUT: указатель найденного элемента списка, либо NULL.         |
//| REMARK: нет.                                                     |
//+------------------------------------------------------------------+
CMyTreeNode* CMyTree::FindByLong(long find_long)
  {
   CMyTreeNode *res=NULL;
   CMyTreeNode *node;
//--- создаем узел дерева для передачи параметра поиска
   node=new CMyTreeNode;
   if(node==NULLreturn(NULL);
   node.SetLong(find_long);
//---
   res=Find(node);
   delete node;
//---
   return(res);
  }
//+------------------------------------------------------------------+
//| скрипт "тестирование класса CMyTree"                             |
//+------------------------------------------------------------------+
//---  массив для инициализации строк
string str_array[11]={"p","oo","iii","uuuu","yyyyy","ttttt","rrrr","eee","ww","q","999"};
//---
int OnStart() export
  {
   int          i;
   uint         pos;
   int          beg_time,end_time;
   CMyTreeNode *node; //--- временный указатель на экземпляр класса CMyTreeNode 
//---  
   printf("Start test %s.",__FILE__);
//--- Наполняем MyTree экземплярами класса MyTreeNode в количестве extCountedNodes.
   beg_time=GetTickCount();
   for(i=0;i<extCountedNodes;i++)
     {
      node=MyTree.CreateElement();
      if(node==NULL)
        {
         //--- аварийный выход
         printf("%s (%4d): create error",__FILE__,__LINE__);
         return(__LINE__);
        }
      NodeSetData(node,i);
      node.SetLong(i);
      MyTree.Insert(node);
     }
   end_time=GetTickCount();
   printf("Время заполнения MyTree %d мс.",end_time-beg_time);
//--- Создаем временное дерево TmpMyTree.
   CMyTree TmpMyTree;
//--- Изымаем 50% элементов из дерева (все четные)
//--- и добавляем их во временное дерево TmpMyTree.
   beg_time=GetTickCount();
   for(i=0;i<extCountedNodes;i+=2)
     {
      node=MyTree.FindByLong(i);
      if(node!=NULL)
         if(MyTree.Detach(node)) TmpMyTree.Insert(node);
     }
   end_time=GetTickCount();
   printf("Время удаления %d элементов из MyTree %d мс.",extCountedNodes/2,end_time-beg_time);
//--- Возвращаем изятое обратно
   node=TmpMyTree.Root();
   while(node!=NULL)
     {
      if(TmpMyTree.Detach(node)) MyTree.Insert(node);
      node=TmpMyTree.Root();
     }
//--- Проверяем работу метода Save(int file_handle);
   int file_handle;
   file_handle=FileOpen("MyTree.bin",FILE_WRITE|FILE_BIN|FILE_ANSI);
   if(file_handle>=0)
     {
      if(!MyTree.Save(file_handle))
        {
         //--- ошибка записи в файл
         //--- аварийный выход
         printf("%s: Error %d in %d!",__FILE__,GetLastError(),__LINE__);
         //--- уходя, закройте файл !!!
         FileClose(file_handle);
         return(__LINE__);
        }
      FileClose(file_handle);
     }
//--- Проверяем работу метода Load(int file_handle);
   file_handle=FileOpen("MyTree.bin",FILE_READ|FILE_BIN|FILE_ANSI);
   if(file_handle>=0)
     {
      if(!TmpMyTree.Load(file_handle))
        {
         //--- ошибка чтения из файла
         //--- аварийный выход
         printf("%s: Error %d in %d!",__FILE__,GetLastError(),__LINE__);
         //--- уходя, закройте файл !!!
         FileClose(file_handle);
         return(__LINE__);
        }
      FileClose(file_handle);
     }
//---
   MyTree.Clear();
   TmpMyTree.Clear();
//---
   printf("End test %s. OK!",__FILE__);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Функция вывода содержимого node в журнал                         |
//+------------------------------------------------------------------+
void NodeToLog(CMyTreeNode *node)
  {
   printf("   %I64d,%f,'%s','%s'",
               node.GetLong(),node.GetDouble(),
               node.GetString(),TimeToString(node.GetDateTime()));
  }
//+------------------------------------------------------------------+
//| Функция "наполнения" node случайными значениями                  |
//+------------------------------------------------------------------+
void NodeSetData(CMyTreeNode *node,int mode)
  {
   if(mode%2==0)
     {
      node.SetLong(mode*MathRand());
      node.SetDouble(MathPow(2.02,mode)*MathRand());
     }
   else
     {
      node.SetLong(mode*(long)(-1)*MathRand());
      node.SetDouble(-MathPow(2.02,mode)*MathRand());
     }
   node.SetString(str_array[mode%10]);
   node.SetDateTime(10000*mode);
  }