拓扑排序(topological sort)DFS

对上图进行拓扑排序的结果:

8->7->2->3->0->6->9->10->11->12->1->5->4

使用dfs进行拓扑排序

同样摘录一段维基百科上的伪码:


L ← Empty list that will contain the sorted nodes
S ← Set of all nodes with no outgoing edges
for each node n in S do
    visit(n) 
function visit(node n)
    if n has not been visited yet then
        mark n as visited
        for each node m with an edgefrom m to ndo
            visit(m)
        add n to L
DFS的实现更加简单直观,使用递归实现。利用DFS实现拓扑排序,实际上只需要添加一行代码,即上面伪码中的最后一行:add n to L。
需要注意的是,将顶点添加到结果List中的时机是在visit方法即将退出之时。
这个算法的实现非常简单,但是要理解的话就相对复杂一点。
关键在于为什么在visit方法的最后将该顶点添加到一个集合中,就能保证这个集合就是拓扑排序的结果呢?
因为添加顶点到集合中的时机是在dfs方法即将退出之时,而dfs方法本身是个递归方法,只要当前顶点还存在边指向其它任何顶点,它就会递归调用dfs方法,而不会退出。因此,退出dfs方法,意味着当前顶点没有指向其它顶点的边了,即当前顶点是一条路径上的最后一个顶点。
 
下面简单证明一下它的正确性:
考虑任意的边v->w,当调用dfs(v)的时候,有如下三种情况:
dfs(w)还没有被调用,即w还没有被mark,此时会调用dfs(w),然后当dfs(w)返回之后,dfs(v)才会返回
dfs(w)已经被调用并返回了,即w已经被mark
dfs(w)已经被调用但是在此时调用dfs(v)的时候还未返回
需要注意的是,以上第三种情况在拓扑排序的场景下是不可能发生的,因为如果情况3是合法的话,就表示存在一条由w到v的路径。而现在我们的前提条件是由v到w有一条边,这就导致我们的图中存在环路,从而该图就不是一个有向无环图(DAG),而我们已经知道,非有向无环图是不能被拓扑排序的。
 
那么考虑前两种情况,无论是情况1还是情况2,w都会先于v被添加到结果列表中。所以边v->w总是由结果集中后出现的顶点指向先出现的顶点。为了让结果更自然一些,可以使用栈来作为存储最终结果的数据结构,从而能够保证边v->w总是由结果集中先出现的顶点指向后出现的顶点。

来自于http://blog.csdn.net/dm_vincent/article/details/7714519

附上我的dfs代码 uva10305

#include<bits/stdc++.h>
using namespace std;
const int maxn=1100;
int c[maxn];
bool G[maxn][maxn];
int topo[maxn],t,n,m,x,y;
bool dfs(int u)
{
    c[u]=-1;//访问标志-1正在访问,1已经访问,0尚未访问
    for(int v=0; v<n; v++)
        if(G[u][v])
        {
            if(c[v]<0) return false;//存在环路
            else if(!c[v]&&!dfs(v)) return false;
        }
    c[u]=1;
    topo[--t]=u;
    return true;
}
bool toposort()
{
    t=n;
    memset(c,0,sizeof(c));
    for(int u=0; u<n; u++)
        if(!c[u]&&!dfs(u))
            return false;
    return true;
}
int main()
{
    while(cin>>n>>m&&n)
    {
        memset(G,0,sizeof(G));
        while(m--)
        {
            cin>>x>>y;
            G[x-1][y-1]=1;
        }
        if(toposort())
            for(int i=0; i<n; i++)
                cout<<topo[i]+1<<(i==n-1?"\n":" ");
        else cout<<"This is not a DAG!"<<endl;
    }
    return 0;
}


在C语言中,使用深度优先搜索(DFS)算法实现拓扑排序通常用于有向无环图(DAG)。这里是一个简单的例子,展示如何通过递归的方式实现: ```c #include <stdio.h> #include <stdlib.h> // 声明邻接表结构 typedef struct { int* adj; // 存储邻居节点索引 int size; // 邻居数量 } Graph; // 用于记录节点是否已经访问过 int visited[100]; // 假设你有最多100个节点 void dfs(int node, Graph* graph) { visited[node] = 1; printf("%d ", node); // 打印节点值 // 遍历当前节点的所有未访问邻居 for (int i = 0; i < graph->size[node]; i++) { if (!visited[graph->adj[node][i]]) { dfs(graph->adj[node][i], graph); // 递归访问邻居 } } } // 拓扑排序函数 void topologicalSort(Graph* graph) { int n = sizeof(visited)/sizeof(visited[0]); // 对所有节点初始化访问状态 for (int i = 0; i < n; i++) { visited[i] = 0; } // 从没有前驱节点的节点开始(即入度为0的节点) for (int i = 0; i < n; i++) { if (visited[i] == 0 && getDegree(i, graph) == 0) { dfs(i, graph); } } } // 获取给定节点的入度 int getDegree(int node, Graph* graph) { return graph->size[node]; } int main() { // 初始化并构建你的邻接列表... Graph g = { ... }; topologicalSort(&g); return 0; } ``` 这个代码首先创建了一个邻接表表示图,然后在`topologicalSort`函数中,使用DFS遍历并打印出每个节点(按照拓扑排序顺序),同时维护了`visited`数组来跟踪节点是否已被访问。 请注意,这个代码简化了许多细节,例如假设输入图已经预处理成邻接列表形式。在实际应用中,你需要根据你的数据结构适当地调整代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值