拓扑排序将有向无环图的所有顶点排成一个线性序列,使得其中任意两个顶点(u、v),若存在有向边(u->v),那么在线性序列中(u)必然在(v)之前。
思想:
- 将所有入度为0的顶点入队;
- 取队首结点输出,删除所有从该结点出发的边,并将这些边到达的顶点的入度减1,若某顶点入度减为0,将其入队;
- 重复2,直到队列为空。若进过队的结点数为(n),排序成功,否则图中有环。
/*复杂度O(V+E)*/
int vertexNum;
vector<int> adjList[MAXV]; //邻接表
int inDegree[MAXV]; //顶点入度,读入时记录
bool topologicalSort()
{
int cnt = 0;
queue<int> q; //若有多个入度为0的顶点要选择编号最小的,可使用priority_queue
//将所有入度为0的顶点入队
for(int i = 0;i < vertexNum;i++)
{
if(inDegree[i] == 0)
q.push(i);
}
while(!q.empty())
{
int front = q.front();
cout << front << endl; //输出拓扑序列
q.pop();
for(int i = 0;i < adjList[front].size();i++)
{
int v = adjList[front][i]; //front的后继结点
inDegree[v]--;
if(indegree[v] == 0)
q.push(v);
}
adjList[front].clear(); //删掉从该顶点出发的所有边
cnt++;
}
if(cnt == vertexNum)
return true;
else
return false;
}
// dfs version, reverse ans is the topological sequence
enum states {UNKNOWN, VISITING, VISITED};
bool hasCycle(vector<vector<int>>& graph, int cur, vector<int>& state, vector<int>& ans) {
if (state[cur] == VISITING) return true;
if (state[cur] == VISITED) return false;
state[cur] = VISITING;
for (auto neighbors : graph[cur]) {
if (hasCycle(graph, neighbors, state, ans))
return true;
}
state[cur] = VISITED;
ans.push_back(cur);
return false;
}