引例:
首先先举一个拓扑排序比较贴近实际的例子吧。比如我想修操作系统这门课,假设学校要求必须先修数据结构和C语言,我必须满足修过数据结构和c语言才可以修操作系统这门课。但是有一个很奇怪的问题就是如果反过来如果要求学C语言和数据结构之前要学操作系统,那么就会出现问题,所以拓扑排序的充要条件就是不能出现回路,即出发点和终点都是自身的情况。
实现:
寻找一个尚未分配拓扑编号的入度为0的顶点,如果不存在这样的顶点,那么可以证明该图肯定存在回路,所以根据算法的流程我们可以依次找出入度为0的顶点,然后删除它和与之相连的边,可以用队列(栈)实现,直到该图所有的点都被删除,程序结束,拓扑排序完毕。
代码:
#include<iostream>
#include<queue>
using namespace std;
const int maxn = 1001;
queue<int> q;
vector<vector<int> >map(maxn,vector<int>(maxn)); //等价于int map[maxn][maxn];
int indegree[maxn];
void topo(int n)
{
for(int i=1;i<=n;i++)
{
if(indegree[i] == 0) //入度为0便可移除出队列
{
q.push(i);
cout<<"V"<<i<<":"<<"enqueue"<<endl;
}
}
int temp;
while(!q.empty())
{
temp = q.front();
q.pop();
cout<<"V"<<temp<<":"<<"dequeue"<<endl;
for(int i=1;i<=n;i++) //遍历从temp出发的每条边,入度--,因为temp所对应的结点被移除了
{
if(map[temp][i]) //因为temp所对的顶点已经被移除,所以移除和它相邻的边
{
indegree[i]--; //与被删除的顶点相邻的顶点的入度要-1
if(indegree[i] == 0) //入度为0的时候将其入队
{
q.push(i);
cout<<"V"<<i<<":"<<"enqueue"<<endl;
}
}
}
//cout<<endl;
}
}
int main()
{
int m,v1,v2;
for(int i=1;i<=7;i++)
{
indegree[i] = 0;
for(int j=1;j<=7;j++)
{
map[i][j] = 0; //初始化各顶点都不连通
}
}
cin>>m; //一共有几条连通
for(int i=0;i<m;i++)
{
cin>>v1>>v2;
map[v1][v2] = 1; //v1和v2之间的边
}
/*
map[1][2] = 1;
map[1][3] = 1;
map[1][4] = 1;
map[2][4] = 1;
map[5][4] = 1;
map[5][7] = 1;
map[7][6] = 1;
map[3][6] = 1;
map[4][3] = 1;
map[4][6] = 1;
map[4][7] = 1;
map[2][5] = 1;
*/
for(int i=1;i<=7;i++)
{
for(int j=1;j<=7;j++)
{
if(map[i][j] == 1)
{
indegree[j]++; //统计每个顶点的入度
}
}
}
for(int i=1;i<=7;i++)
{
cout<<"V"<<i<<"-"<<"InDegree:"<<indegree[i]<<endl; //打印每个顶点的入度
}
topo(7);
}