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 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 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==NULL) return(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);

  }