拓扑排序算法详解

一、定义:是将一个有向无环图G的所有的顶点排成一个线性序列,使得有向图中的任意的顶点u 和 v 构成的弧<u, v>属于该图的边

集,并且使得 u 始终是出现在 v 的前面。通常这样的序列称为是拓扑序列。


注意:

只有有向无环图才可以进行拓扑排序


二、算法思想:

1.找到有向无环图中没有前驱的节点(或者说是入度为0的节点)输入;

2.然后从图中将此节点删除并且删除以该节点为尾的弧;



三、代码实现:

1、邻接矩阵存图:

算法复杂度: 时间复杂度:O(n^2)        空间复杂度:O(n^2)

适合数据较小的题目

题目节选:hdu1285

</pre><pre name="code" class="cpp"><span style="font-size:14px; "></span><pre name="code" class="cpp" style="margin-top: 4px; margin-right: 0px; margin-bottom: 4px; margin-left: 0px; background-color: rgb(240, 240, 240); ">
<pre name="code" class="cpp">#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;


const int maxn = 1000;
int vis[maxn],g[maxn][maxn];//vis标记入度,g邻接矩阵存图

void topsort(int n) {
    int k=0;
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {//找入度是0的节点
            if(!vis[j]) {
                printf("%d%c",j,i==n ? '\n':' ');
                vis[j]--;//删除入 为0的节点并打印,是入度是-1
                k=j;
                break;
            }
        }
        for(int j=1; j<=n; j++) { //找到以该点为尾的边并且删掉从新找入度为0的节点,重复过程
            if(g[k][j]==1) {
                g[k][j]=0;
                vis[j]--; //入度更新为-1
            }
        }
    }
}
int main() {
    int n,m;
    while(~scanf("%d%d",&n,&m)) {
        int x,y;
        memset(vis,0,sizeof(vis));
        memset(g,0,sizeof(g));
        for(int i=1; i<=m; i++) {
            scanf("%d%d",&x,&y);
            if(!g[x][y]) {
                g[x][y]=1;
                vis[y]++;
            }
        }
        topsort(n);
    }
    return 0;
}

2、STL和优先队列

算法复杂度

时间复杂度:O(V+E)

空间复杂度:O(V)

适合数据量稍大的题目


题目引入:

Description

针对计算机系本科课程,根据课程之间的依赖关系(如离散数学应在数据结构之前开设)制定课程安排计划。

Input

第一行为样例组数T。每组样例第一行为课程数量n(1 <= n <= 5000),以下n行每行表示一门课程名称。接下来为关系数量m(1 <= m <= 10000),每一行有两个课程名称a、b,表示a课程要开设在b课程前面。(输入保证无环)

Output

每组样例第一行见输出,以下n行每行输出一个课程名称,描述拓扑排序后的课程表。如果课程优先级相同,则优先输出课程名称字典序小的课程。

Sample Input

16MathChineseEnglishSportsMusicComputer4Chinese EnglishEnglish ComputerMath ComputerMusic Computer

Sample Output

Case 1:ChineseEnglishMathMusicComputerSports

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>

using namespace std;

const int maxn = 5000 + 5;
map <string,int> mp;
vector <int> v[maxn];
string s[maxn];
int vis[maxn],n,m;
int main()
{
    int t,k=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++)
            v[i].clear();
        mp.clear();
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            cin >>s[i];
        }
        sort(s+1,s+n+1);
        for(int i=1;i<=n;i++)
            mp[s[i]]=i;
        scanf("%d",&m);
        for(int i=0;i<m;i++)
        {
            string s1,s2;
            cin >>s1>>s2;
            int t1 = mp[s1];
            int t2 = mp[s2];
            v[t1].push_back(t2);
            vis[t2]++;
        }
        printf("Case %d:\n",++k);
        priority_queue < int,vector<int>,greater<int> > q;
        for(int i=1;i<=n;i++)
        {
            if(!vis[i]) //入度为0就入队
                q.push(i);
        }
        while(!q.empty()) //bfs遍历入度为0的所有的节点
        {
            int x = q.top();
            q.pop();
            printf("%s\n",s[x].c_str());
            for(int i=0;i<v[x].size();i++) //与节点x相邻的节点
            {
                int t = v[x][i]; //以节点x为尾的边
                vis[t]--; //删除该边
                if(!vis[t]) //再将更新后的图的入度为0的节点入队
                    q.push(v[x][i]);
            }
        }
    }
    return 0;
}



    原文作者:排序算法
    原文地址: https://blog.csdn.net/shao1996/article/details/53119224
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞