拓扑排序
用途
将有向无环图的所有顶点排成一个线性序列,且对于图中任意两个顶点u、v,如果存在边 u->v,则保证在线性序列中u一定在v前面。
可以用来判断给定的图中是否存在环。
算法描述
对于结点i,只有当它的所有前驱结点都在序列内后,才能将i加入序列中。根据这个思想,算法具体步骤如下:
- 找到所有入度为0的结点,并将它们入队;
- 队首结点u出队,并使所有u指向的结点v的入度-1,如果v结点变为0,说明v的所有前驱结点已在序列中,将其入队;
- 将u加入序列;
- 重复步骤2-3,直到队空;
- 判断最终序列中结点的个数,如果等于n,则图是有向无环图;如果小于n,说明图中一定有环,则无解,返回false。
代码实现
const int maxn = 1000;
vector<int> adj[maxn]; // 邻接表
int n; // 结点数
int in[maxn]; // 入度数组
bool topoSort()
{
int num = 0; // 记录序列中结点数
queue<int> q;
for (int i = 0; i < n; i++)
if (in[i] == 0) // 入度为0结点入队
q.push(i);
while (!q.empty())
{
int u = q.front(); // 队首结点出队
q.pop();
printf("%d", u); // 输出
for (int i = 0; i < adj[u].size(); i++) // 遍历所有u指向的结点
{
int v = adj[u][i];
in[v]--; // 入度减1
if (in[v] == 0) //入度减为0则入队
q.push(v);
}
num++; // 将结点u加入序列
}
if (num == n) // 全部结点加入序列
return true;
else // 序列中结点数小于n,则一定存在环
return false;
}