一种较为高效的TreeList生成算法(Delphi实现)

记得不久前曾写过篇关于TreeList生成的文章。虽然那个算法里,我已经有对叶节点做判断,避免无用的Filter操作。但是非叶节点的Filter操作依然是无可避免的。而Filter又是影响整个生成的最重要因素,因此当带子节点的节点很多时,速度还是要被拖下去的。

后来我看到了一种觉得不错的思路,就是用调整节点的方法来形成树。先一次过把所有数据当根节点加进TreeList中,然后再根据它们之间的ID和PID关系来进行节点调整,这样就可以避免数据集的Filter操作了。而影响算法的主要因素,变成了查找关系时的IndexOf操作,和节点移动的方法MoveTo,不过相对于Filter来说,这个肯定要更高效了。
 

另一种较为高效的TreeList生成算法(Delphi实现)

算法实现如下:

procedure GenerateTreeListEx(AKeyField, AParentField: string; ADataSet: TDataSet; ATree: TTreeView);

 function CreateNewNode(ADataSet: TDataSet; ATree: TTreeView): TTreeNode;
 var
  pCodeValue: PString;
 begin
  // 这里写你的TreeNode读写逻辑,添加到根节点下就行
  // 现以用Data属性来保存代码值为例,假设代码名字段叫"CodeName",代码值字段叫"CodeValue"
  result := ATree.Add(nil, ADataSet['CodeName']);
  New(pCodeValue);
  pCodeValue^ := ADataSet['CodeValue'] ;
  result.Data := pCodeValue;
 end;

var
 APidList, AItems, AChildItems: TStringList;
 i, j, k, iIndex: integer;
 sPID: string;
begin
 APidList := TStringList.Create;

 APidList.Sorted := true; //把结果进行排序,这样可以通过搜索算法(Find的二分查找)提高索引效率,重要
 ATree.Items.BeginUpdate;
 try
  // 读取数据集
  for i := 1 to ADataSet.RecordCount do
  begin
   if VarIsNull(ADataSet[AParentField]) then
    sPID := 'NULL'
   else
    sPID := ADataSet[AParentField];

   // 查找该PID是不是已经在PidList里存在
   if not APidList.Find(sPID, iIndex) then
    iIndex := APidList.AddObject(ADataSet[AParentField], TStringList.Create);
   with TStringList(APidList.Objects[iIndex]) do
    AddObject(ADataSet[AKeyField], CreateTreeNode(ADataSet, ATree));

   ADataSet.Next;
  end;

  // 调整节点
  for i := 0 to APidList.Count - 1 do
  begin
   AItems := TStringList(APidList.Objects[i]);
   for j := 0 to AItems.Count - 1 do
   begin
    if APidList.Find(AItems[j], iIndex) then
    begin
     AChildItems := TStringList(APidList.Objects[iIndex]);
     for k := 0 to AChildItems.Count - 1 do
      TTreeNode(AChildItems.Objects[k]).MoveTo(TTreeNode(AItems.Objects[j]), naAddChild);

     // 由于MoveTo会导致节点展开,因此把它重新折叠起来

     TTreeNode(AItems.Objects[j]).Collapse(false);
    end;
   end;
  end;
 finally
  // 释放资源等
  for i := 0 to APidList.Count - 1 do APidList.Objects[i].Free;
  APidList.Free;
  ATree.Items.EndUpdate;
 end;
end;

比起上次的方法,除了效率外,我觉得这次的方法代码也更为简洁点,没有用到什么栈结构;也不用什么RootFilterText来过滤根节点了。它能得出哪些是根节点(对于一些丢失父节点的节点,也能自动被处理成根节点),这是我觉得比较好的地方。

猜你喜欢

转载自blog.csdn.net/Harryfin/article/details/84621851