Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从列表中删除树的所有对象的算法_C#_.net_Algorithm_Entity Framework - Fatal编程技术网

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

C# 从列表中删除树的所有对象的算法,c#,.net,algorithm,entity-framework,C#,.net,Algorithm,Entity Framework,我有一个问题,需要从列表中删除树的所有对象 我有一个列表标签,其中包含整个系统中符合特定条件的标签(通常以一些搜索字符串开始)。我还有一个根设备对象。设备类描述如下: public class Device { public int ID; public String Tag; public EntityCollection<Device> ChildDevices; } 公共类设备 { 公共int ID; 公共字符串标签; 公共实体收集设备; } 我所做

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

我有一个
列表标签
,其中包含整个系统中符合特定条件的标签(通常以一些搜索字符串开始)。我还有一个根
设备
对象。
设备
类描述如下:

public class Device
{
    public int ID;
    public String Tag;
    public EntityCollection<Device> ChildDevices;
}
公共类设备
{
公共int ID;
公共字符串标签;
公共实体收集设备;
}
我所做的尝试是使用广度优先搜索,在访问每个节点时从列表中删除标记,然后返回剩余的内容:

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;
}
private List RemoveInvalidTags(设备根目录,列表标签)
{
var queue=新队列();
queue.Enqueue(root);
而(queue.Count>0)
{
var device=queue.Dequeue();
//从DB加载此设备的所有子设备
var childDevices=device.childDevices.ToList();
foreach(childDevices中的var hierarchyItem)
排队(hierarchyItem.ChildDevice);
标签。移除(设备。标签);
}
返回标签;
}
目前,我正在访问2000多个设备节点,并从大约1400个标记的列表中删除(由于搜索字符串而减少)。这大约需要4秒,这太长了

我曾尝试将标签列表更改为哈希集,但它带来的速度改进微不足道


有什么算法/更改的想法可以让我更快吗?

我猜你的树相当“胖”。也就是说,每个节点都有许多子节点,但没有很多层。如果是这样,试试看。您应该快速到达底部,然后能够开始删除节点。您仍然需要访问所有节点,但不必像在BFS中那样存储大量中间数据。

您肯定应该使用某种哈希表(抱歉,不熟悉c#的细节)来访问标记


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

如果需要,您可以使用
秒表来查找瓶颈

var childDevices = device.ChildDevices.ToList();

foreach (var hierarchyItem in childDevices)
   queue.Enqueue(hierarchyItem.ChildDevice);
这是你的瓶颈

看看这个,我希望你已经知道了

你为什么不试试这个

foreach (var hierarchyItem in device.ChildDevices)
   queue.Enqueue(hierarchyItem.ChildDevice);
您不需要将device.ChildDevices转换为list,因为它已经是可枚举的。当您将其转换为列表时,它将是渴望的,这是可枚举的,它将是懒惰的


试试看。

最好插入指令或分析代码,以找出大部分时间的去向。前面关于“将查询加载到数据库”(即
childDevices=device.childDevices.ToList();
)的注释和回答花费时间可能是正确的,但可能是相反的
tags.Remove(device.Tag)O(n)
时间:“此方法执行线性搜索;因此,此方法是一个O(n)操作,其中n是计数。”[MSDN]

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

要避开这个问题:

  • 通过使哈希表H对应于标签列表,对标签列表进行预处理
  • 对于每个device.Tag,测试其哈希值是否为H
  • 如果该值以H为单位,则将device.Tag添加到字典D中
  • 处理完所有设备标签后,对于
    标签
    列表中的每个元素T,如果T在D中,则输出T,否则抑制T

  • 我不认为你能使目前的方法更快。当然,问题在于向数据库加载查询。但是,您可以在数据库本身中执行此操作。如果你需要在一部分设备上操作,你必须写一些智能的东西。可能是一个执行当前逻辑的存储过程。否则,您可以执行如下操作:context.Devices.Select(x=>x.Tag)。其中(tags)并删除这些标记。如果您不使用队列,并执行预排序遍历,如何?这消除了队列,但您的树更像一个trie..@DarthVader-如果我理解正确,使用预排序遍历只需将其更改为DFS,就像建议的ObsureRobot一样,您随后说这不会解决我的问题。预排序遍历与DFS不同,它不使用额外的数据结构。在这种情况下,您将避免ToList()和queue。您可以按顺序或按后顺序进行,这无关紧要,但DFS或BFS不重要。此外,您可能需要考虑更改树结构。使用节点而不是当前的impl.fetching 2000+设备在太多的查询中花费太长时间,您应该更改数据获取的方式,您当前的代码可以稍微改进,但我认为这不是您的问题,最好编写一个递归存储过程……您是对的,我的树只有大约5层深,但有些节点有20多个子节点。我会尝试一下DFS,看看我会怎么做。对我来说,这听起来不像是解决方案,因为他正在为每个节点执行DB请求。2000多个节点对traversalit来说真的不算太多,这不会有什么区别,你的瓶颈是ToList方法,依我看。你为什么不用秒表来找出每件作品的表现呢?是的,你用秒表来计时,你是对的,这是我的瓶颈,尽管我认为这是相当明显的。问题是,我如何构造我的算法来remo