我有一个小问题,我想得到你的意见。
我正在处理文件而不是参考其他文件。从任何文档开始,我需要获取此文档引用的所有文档的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()
{ }
最好的方法是什么?可以实现任何特定的算法吗?
任何建议都被广泛接受!
由于
答案 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;
}