带有访问后排序的图表上的迭代DFS

时间:2018-06-14 11:47:48

标签: algorithm graph-theory kosaraju-algorithm

我目前正试图在有向图上实施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示例:

enter image description here

(我顺时针列出了顶点,所以a = 0,b = 1,c = 2,d = 3,h = 4,g = 5,f = 6,e = 7)

<击>

图表作为邻接列表:

{0} - &gt; {1}

{1} - &gt; {2,6,7}

{2} - &gt; {3,5}

{3} - &gt; {2,4}

{4} - &gt; {3,5}

{5} - &gt; {6}

{6} - &gt; {5}

{7} - &gt; {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是邻居但已经标记为&#34;因为是2 的邻居

输入5

我从堆栈弹出5,现在是{7,6},所有邻居(6)已经&#34;标记为

输入6

我从堆栈弹出6,{7},5已经是#34;标记为&#34;邻居

输入7

我从堆栈弹出7,{empty},邻居(1&amp; 6)已经&#34;标记为&#34;

我的结果数组是0 1 2 3 4 5 6 7因为我&#34;对待&#34;节点是这个顺序(或我的访问后实现7 6 5 4 3 2 1 0)

随着邻居(我的实际DFS)计算顺序的减少,我得到了:

输入0,打开1

stack {} - &gt; {1}

输入1,打开7 6 2

stack {} - &gt; {2,6,7}

输入7

stack {2,6} - &gt; {2,6}

输入6,开5

堆叠{2} - &gt; {2,5}

输入5

堆叠{2} - &gt; {2}

输入2,打开3

stack {} - &gt; {3}

输入3,打开4

stack {} - &gt; {4}

输入4

stack {} - &gt; {}

我得到以下结果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 - &gt; 0,1,7在同一个SCC中,从工作堆栈中删除它们(现在是{6,5,4,3,2})和图形。

打开2,dfs返回3和4 - &gt; 2,3,4在同一个SCC中,从工作堆栈中删除它们(现在是{6,5})和图形。

开放5,dfs返回6 - &gt; 5,6是相同的SCC

2n结果,堆栈{4,3,2,5,6,7,1,0}:

打开0,dfs返回1和7 - &gt; 0,1,7在同一个SCC中,从工作堆栈中删除它们(现在是{4,3,2,5,6})和图形。

开放6,dfs返回5,4,3和2 - &gt; 2,3,4,5,6属于相同的SCC (但是他们是&#39; T)(因为在反向图中,从6开始我变为5然后变为4或2。 ..)

任何人都可以解释为什么计算顶点按升序或递减顺序进入DFS不会得到与Kosaraju算法相同的结果吗?

编辑:我提供了一些关于如何获得结果以及如何手动运行算法的额外信息。希望现在更清楚。

1 个答案:

答案 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数组,但这是我的实际代码,它似乎正在工作。

感谢那些试图帮助我的人。