我目前正试图在有向图上实施Kosaraju算法,以找到所有强连通分量。
我很清楚这个算法是如何工作的,但是在获得DFS结果的访问后顺序时我遇到了一些问题。
目前,我的DFS实现的伪代码如下:
[编辑]:我终于得到了一个DFS版本,其中帖子访问顺序为输出。我想增加一个数字代表"锁定"每次该节点推送DFS堆栈上的邻居时节点的数量。然后,当一个节点的访问结束时(没有更多的邻居要推送),我注意到推动该节点的DFS从该子节点结束(我减少其锁定)。如果此通知也结束了前面的访问,我会前往前一个节点注意它等等......
dfs(G, s):
for all v in vertices :
mark[v] = false
blocked[v] = 0
preceding[v] = -1
mark[s] = true
create a stack P
P.push(s)
while P not empty:
v = P.pop
for all t neighbours of v:
if mark[t] = false:
mark[t] = true
blocked[v]++
preceding[t] = v
P.push(t)
if no neighbours added to the stack:
while(blocked[v] == 0):
result.push(v);
v = (preceding[v] == -1) ? preceding[v] : v
blocked[v]--
但我不确定这种实现是否输出了Kosaraju算法的正确顺序。
我的DFS是否正确?
我的DFS示例:
(我顺时针列出了顶点,所以a = 0,b = 1,c = 2,d = 3,h = 4,g = 5,f = 6,e = 7)
图表作为邻接列表:
{0} - > {1}
{1} - > {2,6,7}
{2} - > {3,5}
{3} - > {2,4}
{4} - > {3,5}
{5} - > {6}
{6} - > {5}
{7} - > {0,6}
我的DFS的另一个问题是我的算法按递减顺序计算邻居。我认为这并不重要,因为邻居实际上是一组顶点,但在我的例子中我遇到了奇怪的问题。
邻居计算顺序增加的解释:
输入0,打开1
我弹出DFS堆栈(是{0}),它返回0.他有1作为邻居,所以我在DFS堆栈上推1(现在是{1})
输入1,打开2 6 7
我从DFS堆栈弹出1,他有2个,6个和7个作为邻居,所以我把它们推到堆栈上(现在是{7,6,2})
输入2,打开3
我从堆栈弹出2(现在是{7,6}),邻居是3和5,我推它们,堆栈是{7,6,5,3}
输入3,打开4
*我从堆栈弹出3(现在是{7,6,5}),4是唯一的一个邻居,我推它,堆栈是{7,6,5,4}
输入4
我从堆栈中弹出4(是{7,6,5}),5是邻居但已经标记为"因为是2 的邻居
输入5
我从堆栈弹出5,现在是{7,6},所有邻居(6)已经"标记为
输入6
我从堆栈弹出6,{7},5已经是#34;标记为"邻居
输入7
我从堆栈弹出7,{empty},邻居(1& 6)已经"标记为"
我的结果数组是0 1 2 3 4 5 6 7因为我"对待"节点是这个顺序(或我的访问后实现7 6 5 4 3 2 1 0)
随着邻居(我的实际DFS)计算顺序的减少,我得到了:
输入0,打开1
stack {} - > {1} 的
输入1,打开7 6 2
stack {} - > {2,6,7}
输入7
stack {2,6} - > {2,6}
输入6,开5
堆叠{2} - > {2,5}
输入5
堆叠{2} - > {2} 的
输入2,打开3
stack {} - > {3}
输入3,打开4
stack {} - > {4}
输入4
stack {} - > {}
我得到以下结果0 1 7 6 5 2 3 4(或4 3 2 5 6 7 1 0进行访问后)
问题是,当我反转图表来计算Kosaraju算法的最后部分时,这两个结果并不相同:
第一个结果(最终获得正确数量的SCC)(堆栈{7,6,5,4,3,2,1,0}):
打开0,dfs返回1和7 - > 0,1,7在同一个SCC中,从工作堆栈中删除它们(现在是{6,5,4,3,2})和图形。
打开2,dfs返回3和4 - > 2,3,4在同一个SCC中,从工作堆栈中删除它们(现在是{6,5})和图形。
开放5,dfs返回6 - > 5,6是相同的SCC
2n结果,堆栈{4,3,2,5,6,7,1,0}:
打开0,dfs返回1和7 - > 0,1,7在同一个SCC中,从工作堆栈中删除它们(现在是{4,3,2,5,6})和图形。
开放6,dfs返回5,4,3和2 - > 2,3,4,5,6属于相同的SCC (但是他们是' T)(因为在反向图中,从6开始我变为5然后变为4或2。 ..)
任何人都可以解释为什么计算顶点按升序或递减顺序进入DFS不会得到与Kosaraju算法相同的结果吗?
编辑:我提供了一些关于如何获得结果以及如何手动运行算法的额外信息。希望现在更清楚。
答案 0 :(得分:0)
这是DFS获得帖子访问顺序的C实现,希望这对某人有用:
typedef struct _graph_list {
int nb_nodes;
int* tab_nodes;
int* succ_list;
} graph_list;
typedef struct _stack {
unsigned int max_capacity;
int* array;
int top_position;
} stack;
int* getSuccFromList(graph_list* graph, int i){
if (graph->tab_nodes[i] == -1) return NULL;
int case_succ = graph->tab_nodes[i];
int next_case_succ = graph->tab_nodes[++i];
while (next_case_succ == -1){
next_case_succ = graph->tab_nodes[++i];
}
int nb_succ = next_case_succ - case_succ;
int j;
int* res = malloc(sizeof(int)*(nb_succ + 1));
for(j = 0; j < nb_succ; j++){
res[j] = graph->succ_list[case_succ + j];
}
res[nb_succ] = -1;
return res;
}
int* dfsPostVisit(graph_list* graph, int vertex){
int i, j, nb_nodes, tmp_v;
int* succ;
int eof_visit;
nb_nodes = graph->nb_nodes;
int* res = malloc(sizeof(int)*(nb_nodes + 1));
int* mark = malloc(sizeof(int)*nb_nodes);
int* blocked = malloc(sizeof(int)*nb_nodes);
int* prec = malloc(sizeof(int)*nb_nodes);
for(i = 0; i < nb_nodes; i++){
res[i] = -1;
mark[i] = 0;
blocked[i] = 0;
prec[i] = -1;
}
res[nb_nodes] = -1;
stack* s = createStack(nb_nodes);
push(s, vertex);
mark[vertex] = 1;
i = 0;
while(!isEmpty(s)){
vertex = pop(s);
succ = getSuccFromList(graph, vertex);
j = 0;
eof_visit = 0;
if(succ!=NULL){
while(succ[j] != -1){
tmp_v = succ[j++];
if(!mark[tmp_v]){
mark[tmp_v] = 1;
blocked[vertex]++;
prec[tmp_v] = vertex;
push(s, tmp_v);
eof_visit++;
}
}
free(succ);
}
if (eof_visit == 0){
while (blocked[vertex] == 0){
res[i++] = vertex;
vertex = (prec[vertex] >= 0)? prec[vertex] : vertex;
blocked[vertex]--;
}
}
}
i = 0;
freeStack(s);
free(mark);
free(blocked);
free(prec);
return res;
}
有些事情可能需要加强,例如使用位数组作为布尔数组而不是int数组,但这是我的实际代码,它似乎正在工作。
感谢那些试图帮助我的人。