簡體   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