假设我有一个xml文档,我可以在其中找到相同类型的其他文档的链接,这些文档也可以链接到另一个文档。在起点我有要阅读和分析的文件清单。我写了以下算法来阅读和分析这些文件:
private static List<String> documentNames = new ArrayList<String>();
main(...) {
//add names to documentNames arrayList above.
for(String documentName : documentNames) {
readDocument(documentName);
}
}
函数readDocument如下所示:
private static CopyOnWriteArrayList<String> visitURL(String documentName) {
CopyOnWriteArrayList<String> visitedDocs = new CopyOnWriteArrayList<String>(); //visited Ref urls
if (!visitedDocs .contains(documentName)) {
analyseAndWriteOnDisk(documentName) //it saves analised document on disk
CopyOnWriteArrayList<String> tmp = visitURL(documentName);
visitedDocs.addAll(tmp);
} else {
System.out.println(documentName " - I have seen it !");
}
return visitedDocs;
}
它有效,但在执行程序后,我可以找到重复的文件(具有相同内容的文件)。我不应该拥有它们 - 我通过函数visitURL中的if-condition来阻止它。我的问题是:这里有什么用?我认为使用数组visitedDocs进行操作有问题。如何在已经访问过的文件的每个递归调用实际版本的数组中使用?
尽可能精确,我有一个递归函数,它对一些集合X进行操作:
recursion(CollectionType X) {
someoperations(X)
recursion(X)
}
且X
必须始终是实际的。
答案 0 :(得分:0)
每次拨打visitURL
时,您都会创建visitedDocs
的新实例。因此,每次在调用开始时它都是空的,并且最后只包含tmp
的当前迭代。
根据JavaDocs,您需要像这样调用新的:
CopyOnWriteArrayList<String> visitedDocs = new CopyOnWriteArrayList<String>(documentNames) //here you need to add the parameter of the ArrayList you want to copy, otherwise you're instantiating a blank ArrayList.
然后,您需要将documentNames
设置为等于返回的visitedDocs
。
答案 1 :(得分:0)
您不应该使用递归算法。使用包含要分析的所有文档的队列以及包含已分析的所有文档的集合更容易。只要队列不为空,就可以从中提取文档,对其进行分析,并将已提取的链接添加到队列中(如果尚未访问)。
private Collection<String> visit(Collection<String> intialDocs) {
Queue<String> documents = new LinkedBlockingQueue(initialDocs);
Set<String> visited = new HashSet<>();
while (!documents.isEmpty()) {
String doc = documents.poll();
visited.add(doc);
Collection<String> links = analyzeDocument(doc);
for(String link : links) {
if (!visited.contains(link) documents.add(link);
}
}
return visited;
}
private Collection<String> analyzeDocument(String document) {
// TODO: analyze document and return a list of all links in that document
}
用法:
Set<String> allVisitedDocuments = visit(documentNames);
这种迭代方法优于递归解决方案:
Stack
这样的LIFO,则会获得深度优先,而某些优先级队列可能会让您根据文档类型决定等等。)注意:如果您不使用多个主题,则应不使用CopyOnWriteArrayList
,因为它会在每个上创建其内部内容的完整副本访问!