繁体   English   中英

从列表中删除树的所有对象的算法

[英]Algorithm to remove all objects of a tree from a list

我有一个需要从列表中删除树的所有对象的问题。

我有一个List<String> Tags ,其中包含整个系统中符合特定条件的标记(通常以某些搜索字符串开头)。 我也有一个根Device对象。 Device类的描述如下:

public class Device
{
    public int ID;
    public String Tag;
    public EntityCollection<Device> ChildDevices;
}

我所做的尝试是使用广度优先搜索,并在访问每个节点时从列表中删除标签,然后返回剩余的内容:

private List<String> RemoveInvalidTags(Device root, List<String> tags)    
{
    var queue = new Queue<Device>();
    queue.Enqueue(root);

    while (queue.Count > 0)
    {
        var device = queue.Dequeue();
        //load all the child devices of this device from DB
        var childDevices = device.ChildDevices.ToList();

        foreach (var hierarchyItem in childDevices)
            queue.Enqueue(hierarchyItem.ChildDevice);

        tags.Remove(device.Tag);
    }

    return tags;
}

目前,我正在访问2000多个设备节点,并从大约1400个标签的列表中删除(由于搜索字符串而减少)。 这大约需要4秒钟,太长了。

我曾尝试将标签列表更改为哈希集,但它带来的速度改进可忽略不计。

关于算法/更改的任何想法,我可以用来使其更快?

我猜你的树很“胖”。 也就是说,您的每个节点都有许多子级,但是您没有很多层。 如果是这种情况,请尝试“ 深度优先搜索” 您应该快速到达最低点,然后能够开始删除节点。 您仍然必须访问所有节点,但是不必像在BFS中那样存储尽可能多的中间数据。

您绝对应该使用某种哈希表(对不起,不熟悉c#的细节)来访问标签。

我对从数据库加载子设备的过程感到好奇。 由于您要遍历整个树,因此您可能能够将大小更大的块加载到内存中。 广度优先搜索可能会在开始从队列中删除节点之前(如果树很宽)将大多数树加载到内存中。

您可以使用Stopwatch来了解瓶颈,如果您问我

var childDevices = device.ChildDevices.ToList();

foreach (var hierarchyItem in childDevices)
   queue.Enqueue(hierarchyItem.ChildDevice);

那就是你的瓶颈。

看一下C#中的Tree实现 ,希望您已经了解Tree Traversals

你为什么不尝试这个?

foreach (var hierarchyItem in device.ChildDevices)
   queue.Enqueue(hierarchyItem.ChildDevice);

您不需要将device.ChildDevices转换为list,因为它已经可以枚举。 当您将其转换为列表时,它会很渴望,这很枚举,会很懒。

试试看

最好对代码进行分析或配置,以找出大部分时间在哪里。 关于“向数据库加载查询”( childDevices = device.ChildDevices.ToList(); )花费时间的早期注释和答案可能是正确的,但似乎有可能是
tags.Remove(device.Tag); 那是浪费时间。 .Remove()对每个排队的项目完成。 删除需要O(n)时间:“此方法执行线性搜索;因此,此方法是O(n)运算,其中n为Count。” [MSDN]

也就是说,假设您排队了m设备项,其中许多设备项具有.Tag不在n个条目的tags列表中。 当查找不在列表中的.Tag时,.Remove会触摸tags每个元素; 平均而言,它会查看n/2个条目以找到列表中的.Tag,因此总工作量为O(m*n) 相比之下,以下方法的工作量为O(m + n) ,通常会小数百倍。

要回避问题:

  1. 通过制作与之对应的哈希表H来预处理tags列表
  2. 对于每个device.Tag,测试其哈希值是否在H中
  3. 如果值在H中,则将device.Tag添加到字典D中
  4. 处理完所有device.Tag之后,对于tags列表的每个元素T,如果T在D输出T中,则抑制T

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM