无环有向图可以进行拓扑排序,形象一点说就是,很多件有依赖关系的工作,怎么安排才能一步步进行下去。
拓扑排序的思想很简单,使用邻接表存储图的话,拓扑排序在O(|V|+|E|)的时间内可以完成。下面介绍两种拓扑排序方法。
1、简单的拓扑排序
首先,找出所有入度为0的节点,放入一个队列,然后,取出一个入度为零的节点,删除该节点以及该节点与其它节点的边,将新产生的入度为0的节点加入队列,最后当队列为空且处理完了所有节点则完成了拓扑排序,否则说明有环。
2、基于DFS的拓扑排序
拓扑排序可以简单的使用一次DFS来完成,将节点按照DFS完成时间逆序排即可获得一个拓扑排序的结果,但是在DFS过程中需要记录是否有环,即使有环也能得到一个拓扑排序,忽略了部分依赖条件。
void top_sort1_graph(struct graph *g)
{
queue<size_t> q;
size_t counter = 0;
size_t *topnum = new size_t[g->n];
size_t *indegree = new size_t[g->n];
for (size_t i = 0; i < g->n; i++) {
indegree[i] = g->v[i].indegree;
if (indegree[i] == 0)
q.push(i);
}
while (!q.empty()) {
size_t id = q.front();
struct vertex &v = g->v[id];
struct edge *e = v.next;
while (e) {
if (--indegree[e->id] == 0)
q.push(e->id);
e = e->next;
}
topnum[counter++] = id;
q.pop();
}
cout << "top sort1: ";
if (counter != g->n) {
cout << "graph has a cycle.";
} else {
for (size_t i = 0; i < g->n; i++) {
cout << g->v[topnum[i]].name;
if (i != g->n - 1)
cout << ", ";
}
}
cout << endl;
delete [] indegree;
delete [] topnum;
}
void top_sort2_graph(struct graph *g)
{
const size_t white = 0, gray = 1, black = 2;
size_t counter = 0;
size_t *vert = new size_t[g->n];
size_t *flag = new size_t[g->n];
for (size_t i = 0; i < g->n; i++) {
flag[i] = white;
}
for (size_t i = 0; i < g->n; i++) {
if (flag[i] != white)
continue;
stack<size_t> s;
flag[i] = gray;
s.push(i);
while (!s.empty()) {
size_t id = s.top();
struct edge *e = g->v[id].next;
while (e) {
if (flag[e->id] == white) {
flag[e->id] = gray;
s.push(e->id);
e = g->v[e->id].next;
} else {
e = e->next;
}
}
id = s.top();
flag[id] = black;
vert[counter++] = id;
s.pop();
}
}
cout << "top sort2: ";
for (size_t i = counter; i != 0; i--) {
cout << g->v[vert[i-1]].name;
if (i != 1)
cout << ", ";
}
cout << endl;
delete [] vert;
delete [] flag;
}