什么是拓扑排序?
给定一个包含 n个节点的有向图 G,我们给出它的节点编号的一种排列,如果满足:
对于图 G中的任意一条有向边 (u,v),u在排列中都出现在 v 的前面,这就是拓扑排序
因此我们可以从中得到两个结论:
1,如果图G中存在环,那肯定没有拓扑排序。
2,如果图 G 是有向无环图,那么它的拓扑排序可能不止一种。举一个最极端的例子,如果图 G包含 n 个节点却没有任何边,那么任意一种编号的排列都可以作为拓扑排序。
例题:
课程表1 :
思路:深度优先
假设我们当前搜索到了节点u,如果他的相邻节点都已经搜索完毕,那么这些节点都已经在栈中,此时u可以入栈,此时u处于栈顶的状态,对于u这个节点,满足拓扑排序的要求。
因此,我们对图进行一遍深度优先搜搜,当每个节点进行回溯时,我们把该节点放入栈,最终从栈顶到栈底就是一种拓扑排序。
show show code:
int** edges;
int* edgeColSize;
int* visited;
bool valid;
void dfs(int u) {
visited[u] = 1;
for (int i = 0; i < edgeColSize[u]; ++i) {
if (visited[edges[u][i]] == 0) {
dfs(edges[u][i]);
if (!valid) {
return;
}
} else if (visited[edges[u][i]] == 1) {
valid = false;
return;
}
}
visited[u] = 2;
}
bool canFinish(int numCourses, int** prerequisites, int prerequisitesSize, int* prerequisitesColSize) {
valid = true;
edges = (int**)malloc(sizeof(int*) * numCourses);
for (int i = 0; i < numCourses; i++) {
edges[i] = (int*)malloc(0);
}
edgeColSize = (int*)malloc(sizeof(int) * numCourses);
memset(edgeColSize, 0, sizeof(int) * numCourses);
visited = (int*)malloc(sizeof(int) * numCourses);
memset(visited, 0, sizeof(int) * numCourses);
for (int i = 0; i < prerequisitesSize; ++i) {
int a = prerequisites[i][1], b = prerequisites[i][0];
edgeColSize[a]++;
edges[a] = (int*)realloc(edges[a], sizeof(int) * edgeColSize[a]);
edges[a][edgeColSize[a] - 1] = b;
}
for (int i = 0; i < numCourses && valid; ++i) {
if (!visited[i]) {
dfs(i);
}
}
for (int i = 0; i < numCourses; i++) {
free(edges[i]);
}
free(edges);
free(edgeColSize);
free(visited);
return valid;
}