拓扑排序入门(真的很简单)

2019-12-30 17:38:01 浏览数 (1)

在一个有向图中,对所有的节点进行排序,要求没有一个节点指向它前面的节点。

先统计所有节点的入度,对于入度为0的节点就可以分离出来,然后把这个节点指向的节点的入度减一。

一直做改操作,直到所有的节点都被分离出来。

如果最后不存在入度为0的节点,那就说明有环,不存在拓扑排序,也就是很多题目的无解的情况。

下面是算法的演示过程。

下面是我以前的写法,比较好理解,但是效率低

代码语言:javascript复制
 //b[]为每个点的入度
for(i=1;i<=n;i  ){
   for(j=1;j<=n;j  ){
      if(b[j]==0){   //找到一个入度为0的点
        ans=j;
        vis[cnt  ]=j;
        b[j]--;
        break;
       }
    }
    for(j=1;j<=n;j  )
        if(a[ans][j]) b[j]--; //与入度为0的点相连的点的入度减一
}
    printf("%d",vis[0]);
    for(i=1;i<cnt;i  ) printf(" %d",vis[i]);
    printf("n");

下面是我现在一直以来的写法,O(V E)。点数 边书

代码语言:javascript复制
    queue<int>q;
    vector<int>edge[n];
    for(int i=0;i<n;i  )  //n  节点的总数
        if(in[i]==0) q.push(i);  //将入度为0的点入队列
    vector<int>ans;   //ans 为拓扑序列
    while(!q.empty())
    {
        int p=q.front(); q.pop(); // 选一个入度为0的点,出队列
        ans.push_back(p);
        for(int i=0;i<edge[p].size();i  )
        {
            int y=edge[p][i];
            in[y]--;
            if(in[y]==0)
                q.push(y);  
        }
    }
    if(ans.size()==n)   
    {
        for(int i=0;i<ans.size();i  )
            printf( "%d ",ans[i] );
        printf("n");
    }
    else printf("No Answer!n");   //  ans 中的长度与n不相等,就说明无拓扑序列

有些拓扑排序要求字典序最小什么的,那就把队列换成优先队列就好了。

0 人点赞