循环引用列表的问题

时间:2011-07-01 08:08:24

标签: c# list circular-reference

我有一个小问题,我想得到你的意见。

我正在处理文件而不是参考其他文件。从任何文档开始,我需要获取此文档引用的所有文档的ID。问题是循环引用是允许的,所以如果A ref B ref C,C又可以引用A并且我进入循环。 如何在C#中解决这个问题?

一个小例子:

假设这是一个代表文档的类:

public class Document
{
    public Document(int id)
    {
        this.ID = id;
    }

    private int m_ID;

    public int ID
    {
        get { return m_ID; }
        set { m_ID = value; }
    }

    private List<Document> m_Children = new List<Document>();

    public List<Document> Children
    {
        get { return m_Children; }
        set { m_Children = value; }
    }

    private List<Document> m_Parent = new List<Document>();

    public List<Document> Parent
    {
        get { return m_Parent; }
        set { m_Parent = value; }
    }

    public Document AddChild(Document child)
    {
        child.Parent.Add(this);
        this.Children.Add(child);

        return child;
    }

    public Document AddChild(int child)
    {
        Document d = new Document(child);

        return AddChild(d);
    }
}

现在让我们创建一个包含一些引用的Document类:

public static Document CreateReferences()
{
    Document d = new Document(1);

    Document temp = d.AddChild(2);

    for (int i = 3; i < 6; i++)
    {
        temp = temp.AddChild(i);
    }

    temp.AddChild(d);

    return d;
}

现在我需要在Document类中实现一个方法,如

public List<int> GetReferencedDocuments()
{    }

最好的方法是什么?可以实现任何特定的算法吗?

任何建议都被广泛接受!

由于

4 个答案:

答案 0 :(得分:4)

任何树遍历算法都没问题。


除了要构建的文档列表外,还要维护一个尚未检查的文档队列,将第一个文档添加到该列表中。

然后,当队列不为空时,获取下一个文档,如果它不在您的列表中,则添加它,并将所有引用的文档添加到您的队列中。


List<Document> FoundDocs = new List<Documents();
Queue<Document> DocsToSearch = new Queue<Document>();

DocsToSearch.Enqueue(StartDoc);

while(DocsToSearch.Count != 0)
{
    Document Doc = DocsToSearch.Dequeue();
    if(!FoundDocs.Contains(Doc))
    {
        FoundDocs.Add(Doc);
        foreach(var ChildDoc in Doc.Children)
        {
            DocsToSearch.Enqueue(ChildDoc);
        }
    }
}

答案 1 :(得分:0)

答案 2 :(得分:0)

有两种主要方法可以解决递归数据的这种递归搜索:标记或记录。

标记:每次列出文档时,将其标记为已查看。不要处理被标记的文件。

所以你的GetReferenceDocuments看起来有点像这样:

  

GetReferencedDocuments(起始点)

     

if(startpoint.flagged)返回null

     

startpoint.flag

     

新列表结果=起点

     

foreach(

中的子文档      

documents.children)

     

result.append(getreferenceddocuments(子文档))//   如果不为空

记录:类似的方法,但标志指示符被已经引用的文档列表(可能是单独的ID列表)替换,并且标记检查是在此列表中搜索此文档。

无论哪种方式都可行,具体取决于您的物体,尺寸和比例。如果无法更改文档对象,则必须列出它们。如果您的扫描中可能有1M个文档,则不希望列出它们。

答案 3 :(得分:0)

示例实施:

public List<int> GetReferencedDocuments()
{    
    var referencedIds = new List<int>();
    var queue = new Queue<Document>(this);
    while (queue.Count > 0)
    {
         var newDocuments = queue.Dequeue().Children
                                           .Where(d => !referencedIds.Contains(d.ID))
         foreach (Document newDocument in newDocuments) 
         {
             queue.Enqueue(newDocument);
             referencedIds.Add(newDocument.ID);
         }
    }
    return referencedIds;
}