Algorithm 使用DFS的图遍历
我正在学习Steven S.Skiena的算法设计手册中的图形遍历。在他的书中,他提供了使用dfs遍历图的代码。下面是代码Algorithm 使用DFS的图遍历,algorithm,depth-first-search,Algorithm,Depth First Search,我正在学习Steven S.Skiena的算法设计手册中的图形遍历。在他的书中,他提供了使用dfs遍历图的代码。下面是代码 dfs(graph *g, int v) { edgenode *p; int y; if (finished) return; discovered[v] = TRUE; time = time + 1; entry_time[v] = time; process_verte
dfs(graph *g, int v)
{
edgenode *p;
int y;
if (finished) return;
discovered[v] = TRUE;
time = time + 1;
entry_time[v] = time;
process_vertex_early(v);
p = g->edges[v];
while (p != NULL) {
/* temporary pointer */
/* successor vertex */
/* allow for search termination */
y = p->y;
if (discovered[y] == FALSE) {
parent[y] = v;
process_edge(v,y);
dfs(g,y);
}
else if ((!processed[y]) || (g->directed))
process_edge(v,y);
}
if (finished) return;
p = p->next;
}
process_vertex_late(v);
time = time + 1;
exit_time[v] = time;
processed[v] = TRUE;
}
在无向图中,下面的代码似乎处理了两次边(调用方法process_edge(v,y)。一次遍历顶点v,另一次处理顶点y)所以我添加了条件
parent[v]=y
在中,如果((!processed[y])| |(g->directed))
它只处理边缘一次。然而,我不知道如何修改此代码以使用并行边和自循环边。代码应处理平行边和自循环 简短答复: 将
(!processed[y])
替换为(!processed[y])
,而不是将其添加到条件中
详细答复:
在我看来,书中所写的实现中有一个错误,您发现并修复了这个错误(除了平行边。下面将详细介绍)。有向图和无向图的实现都应该是正确的,它们之间的区别记录在g->directed
布尔属性中
在书中,就在实施之前,作者写道:
深度优先搜索的另一个重要特性是它将
无向图的边分为两类:树边和后边。这个
树边发现新的顶点,并且是在父关系中编码的顶点。返回
边的另一个端点是展开顶点的祖先,
于是他们指向树上
因此,假设条件(!processed[y])
处理无向图(就像条件(g->directed)
处理有向图一样),允许算法处理后边的边,并防止其重新处理树边(在相反方向)。但是,正如您所注意到的,当通读具有此条件的子级时,树边被视为后边,因此您应该用建议的(父级[v]!=y)
替换此条件
只要没有平行边,算法读取无向图时,条件(!processed[y])
始终为真(进一步详细说明为什么为真-*)。如果存在平行边-在第一次“复制”后读取的平行边将产生false
,并且在应该处理的时候,不会处理该边。但是,您建议的条件将区分树边和其他边(后边、平行边和自循环),并允许算法仅处理那些不是相反方向的树边
要引用自边,它们在新条件和旧条件下都应该可以:它们是具有y==v
的边。到达它们时,y
被发现(因为v
在通过其边缘之前被发现),未被处理(v
仅作为最后一行处理-在通过其边缘之后),并且它不是v
的父级(v
不是它自己的父级)
*通过
v
的边缘,算法读取已发现的y
的该条件(因此它不会进入第一个条件块)。如上所述(在这本书中,我将在本脚注末尾提供一个半证明),p
是树边或后边。当发现y
时,它不能是从v
到y
的树边。它可以是祖先的后缘,这意味着调用是在某个点开始处理此祖先的递归调用中,因此祖先的调用尚未到达最后一行,将其标记为已处理(因此仍将其标记为未处理),它可以是从y
到v
的树边,在这种情况下,相同的情况仍然存在,y
仍被标记为未处理
每个边都是树边或后边的半证明:
为什么边不能转到兄弟节点或表亲节点而不是祖先节点?
从给定顶点v可以到达的所有节点在我们完成
从v进行遍历,因此这种拓扑对于无向图是不可能的
你说得对
引述:
(*)第171页,第2行——dfs代码有一个bug,每个树的边缘
在无向图中处理两次。这项测试需要改进
被加强为:
else if (((!processed[y]) && (parent[v]!=y)) || (g->directed))
至于循环-参见条件(!processed[y])
将始终为真,这也是我的结论!