假设您想在访问图中的每个节点时执行通知。简单的递归实现是:
void DFSRecursive(Node n, Set<Node> visited) {
visited.add(n);
for (Node x : neighbors_of(n)) { // iterate over all neighbors
if (!visited.contains(x)) {
DFSRecursive(x, visited);
}
}
OnVisit(n); // callback to say node is finally visited, after all its non-visited neighbors
}
好的,现在您需要一个基于堆栈的实现,因为您的示例不起作用。例如,复杂的图表可能会导致程序堆栈崩溃,您需要实现一个非递归版本。最大的问题是知道何时发出通知。
以下伪代码有效(Java 和 C++ 混合使用以提高可读性):
void DFS(Node root) {
Set<Node> visited;
Set<Node> toNotify; // nodes we want to notify
Stack<Node> stack;
stack.add(root);
toNotify.add(root); // we won't pop nodes from this until DFS is done
while (!stack.empty()) {
Node current = stack.pop();
visited.add(current);
for (Node x : neighbors_of(current)) {
if (!visited.contains(x)) {
stack.add(x);
toNotify.add(x);
}
}
}
// Now issue notifications. toNotifyStack might contain duplicates (will never
// happen in a tree but easily happens in a graph)
Set<Node> notified;
while (!toNotify.empty()) {
Node n = toNotify.pop();
if (!toNotify.contains(n)) {
OnVisit(n); // issue callback
toNotify.add(n);
}
}
它看起来很复杂,但存在发出通知所需的额外逻辑,因为您需要以访问的相反顺序进行通知 - DFS 从根开始但最后通知它,这与 BFS 不同,实现起来非常简单。
对于踢球,请尝试以下图表:
节点是 s、t、v 和 w。
有向边是:
s->t、s->v、t->w、v->w 和 v->t。
运行您自己的 DFS 实现,访问节点的顺序必须是:
w, t, v, s
DFS 的笨拙实现可能会首先通知 t,这表明存在错误。 DFS 的递归实现总是最后到达 w。