访客设计模式与深度优先搜索之间的区别?

时间:2011-06-09 20:52:50

标签: oop search design-patterns tree visitor-pattern

深度优先搜索似乎能够执行与访客设计模式类似的功能。访问者允许您根据需要定义一些数据结构并在这些结构上添加操作(以多个访问者的形式),而无需修改结构本身。 wikipedia上提供了访客模式的说明。如果我们在数据结构上进行深度优先搜索(或任何其他图搜索算法,如广度优先搜索),并且每次找到结构的元素时,我们运行所需的操作,那么这似乎执行与访客。例如,考虑一棵树。即使树的某些节点具有不同的类型,我们仍然可以在执行DFS时检查节点类型,然后根据节点类型执行不同的操作。

8 个答案:

答案 0 :(得分:4)

您可以在没有DFS的情况下实施访客。同样,您可以在不使用访问者模式的情况下执行DFS。它们是完全分开的。

我恰好认同它们可以以优雅的方式一起使用。

作为一个注释,对于规范的访问者模式,被访问的对象需要实现某种AcceptVisitor接口 - 在您的问题中,“不修改结构本身”的条款让我质疑您是否在做这一点。

答案 1 :(得分:4)

深度优先搜索就是 - 搜索。访问者模式与深度优先搜索正交,在某种意义上,访问者不一定关心遍历树的 ;它只知道它需要对每个节点执行什么操作。

答案 2 :(得分:1)

让我在代码中回答这个问题:

/**
 * This method makes it easier for a class to process all
 * the nodes in an item. The class should implement
 * the NodeVisitor interface. This method will cause the 
 * NodeVisitor.processNode() method to be called once for each
 * node in this item. 
 * @param visitor the class that will visit each node
 * @throws PipelineException some recoverable exception
 */
public void visitNodes(NodeVisitor visitor) throws PipelineException {
    visitNodes(visitor, root);
}

private void visitNodes(NodeVisitor visitor, Node node) throws PipelineException {
    visitor.processNode(node);
    if (node.hasChildren()) {
        int childCount = node.getChildCount();
        NodeList children = node.getChildren();
        for (int i = 0; i < childCount; i++) {
            visitNodes(visitor, children.get(i));
        }
    }
}

/**
 * Classes that implement this interface can be used with
 * Item.visitNodes(). This method provides a convenient
 * way to iterate over all the nodes in an item.
 */
public interface NodeVisitor {
        public void processNode(Node node) throws PipelineException;
}

在这种情况下,visitNodes()方法实现深度优先搜索,但不必。它可以实现任何命中所有节点的搜索。它是visitNodes()方法和NodeVisitor接口的组合,它们构成了“访问者模式”(或者它的一个特定表现形式)。

设计模式和搜索算法之间没有“权衡”。设计模式只是使算法更容易使用。

答案 3 :(得分:0)

在图论中,您可以构建一个图形,使得最小生成树不是深度优先搜索的路径,精确度是非路径:https://cs.stackexchange.com/questions/6749/depth-first-search-to-find-minimum-spanning-tree。我认为你不能将它应用于设计模式。

答案 4 :(得分:0)

深度优先搜索是一种“算法”,访客模式是一种忘记算法问题并专注于要执行的操作的方法。

实际上,访问者模式可能是索引内容的好方法,因为它提供了“与结构无关”的行为(您可以在不重写访问者的情况下更改结构)

但如果您想执行搜索,我建议您不要使用它。任何搜索算法都与特殊类型的结构(树,有向图,流图等)相关

在某些情况下,您可以使用访客模式实现深度优先搜索,但这不是此模式的目的。

访问者模式的使用不依赖于您正在使用的解析类型,而是必须为执行解析。

答案 5 :(得分:0)

visitor实例可以选择访问其子节点但是它希望并且不受深度优先搜索的遍历顺序的约束。 (例如,它可以使用呼吸优先搜索)

另外要提到的是,遍历的结构不需要是显式树。我已经实现了访问迭代结构数据的访问者,这些数据根本不像树。我在那个实例中使用了一个访问者,因为我可以隐藏我正在解析的文件的复杂二进制格式,并允许客户端控制他们想要解析的结构的哪些部分而不需要他们知道文件格式规范。

答案 6 :(得分:0)

我也接受了NRITH的答案,因为访问者模式知道'只有在该访问者的基础上如何处理,访问者才能'定义新操作而不更改类的它运行的元素“,DFS讨论了如何执行节点搜索。但是,为了执行深度遍历和短路分支遍历,我们使用分层访问者模式http://c2.com/cgi/wiki?HierarchicalVisitorPattern)。

您还可以查看When should I use the Visitor Design Pattern?,其中讨论了访客模式/ DFS /分层访问者模式之间的关系。

答案 7 :(得分:0)

Erich Gamma等人的“设计模式”中描述的访客模式为(第一个?)。人。不一定包括在accept方法中遍历数据结构的遍历。虽然这是一个非常方便的组合,但在本书的示例代码章节末尾有一个外部迭代的明确示例。

正如其他人已经说过的那样,在accept方法之外实现的深度优先遍历仍然可以实现访问者模式。那么问题是,与直接调用visitor.visitElement(element)相比,调用element.accept(visitor)之间又有什么区别,而后者直接调用visitor.visitElement(me)? 我只能看到人们可能想要做的两个原因:

  1. 你不能或不想找出具体的元素类,并且通过愚蠢地调用element.accept(visitor),元素本身必须决定visitor.visitElement或者是visitor.visitAnotherElement是要调用的正确操作。

  2. 某些元素是复合材料,无需外部访问所包含的内部元素,并且访问者操作是为内部元素定义的。因此,accept方法将遍历内部元素并调用visitor.visitInnerElement(innerElement)。而且,由于您没有从外部获取内部元素,您也无法从外部调用visitor.visitInnerElememt(innerElement)。

  3. 总结:如果你有一个很好的封装遍历算法,你可以传入一个类似“访问者”的类,并且能够根据遍历期间遇到的对象类型调度到匹配的访问方法,你可以不需要打扰接受方法。您仍然可以通过添加新的Visitor实现来添加新操作,而无需触及您的数据结构和遍历算法。这仍然应该被称为访客模式是一个非常学术讨论。 我认为在大多数情况下,如果accept方法的实现还包括遍历,那么使用accept方法的麻烦才有意义。