CTree

CTree 类是 CTreeNode 类及其子类的样本二叉树。

描述

类 CTree 可供操作 CTreeNode 类及其子类的样本二叉树。在类中, 实现了三元素添加/插入/删除选项以及搜索二叉树。此外, 还实现了文件操作方法。

注释, 在类 CTree 没有实现内存管理机制 (这点与类 CListCArrayObj 不同)。所有树节点被删除时内存一并释放。

声明

   class CTree : public CTreeNode

标称库文件

   #include <Arrays\Tree.mqh>

继承体系

  CObject

      CTreeNode

          CTree

类方法

属性

 

Root

获取树的根节点

创建一个新元素

 

CreateElement

创建一个新节点实例

填充

 

Insert

在树中添加节点

删除

 

Detach

从树里分离一个指定节点

删除

从树里删除一个指定节点

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 2000-2024, MetaQuotes Ltd. |
//| 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 derived from CTree。                      |
//+------------------------------------------------------------------+
//| Class CMyTree.                                                   |
//| 目的: 构造并遍历二叉树。   |
//+------------------------------------------------------------------+
class CMyTree : public CTree
  {
public:
   //--- 以自定义数据搜索二叉树的方法
   CMyTreeNode*        FindByLong(long find_long);
   //--- 创建树元素的方法
   virtual CTreeNode *CreateElement();
  };
//---
CMyTree MyTree;
//+------------------------------------------------------------------+
//| 创建新的树节点。                                    |
//| 输入:  无。                                                   |
//| 输出: 成功则为新树节点指针, 或是 NULL。            |
//| 备注: 无。                                                   |
//+------------------------------------------------------------------+
CTreeNode *CMyTree::CreateElement()
  {
   CMyTreeNode *node=new CMyTreeNode;
//---
   return(node);
  }
//+------------------------------------------------------------------+
//| 按照值 m_long 在列表里搜索元素。                    |
//| 输入:  find_long - 搜索值。                             |
//| 输出: 发现的元素指针, 或是 NULL。               |
//| 备注: 无。                                                   |
//+------------------------------------------------------------------+
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("开始测试 %s。",__FILE__);
//--- 用数量为 extCountedNodes 的 MyTreeNode 类样本填满 MyTree。
   beg_time=GetTickCount();
   for(i=0;i<extCountedNodes;i++)
     {
      node=MyTree.CreateElement();
      if(node==NULL)
        {
         //--- 紧急出口
         printf("%s (%4d): 创建错误",__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("从 MyTree 删除 %d 元素的时间是 %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: 错误 %d 为 %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: 错误 %d 为 %d!",__FILE__,GetLastError(),__LINE__);
         //--- 离开前关闭文件!!!
         FileClose(file_handle);
         return(__LINE__);
        }
      FileClose(file_handle);
     }
//---
   MyTree.Clear();
   TmpMyTree.Clear();
//---
   printf("测试结束 %s。OK!",__FILE__);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| 节点内容输出至日志功能                   |
//+------------------------------------------------------------------+
void NodeToLog(CMyTreeNode *node)
  {
   printf("   %I64d,%f,'%s','%s'",
               node.GetLong(),node.GetDouble(),
               node.GetString(),TimeToString(node.GetDateTime()));
  }
//+------------------------------------------------------------------+
//| 用随机值 "填充" 节点功能                 |
//+------------------------------------------------------------------+
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);
  }