一、拓扑排序
百度百科:对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
简单讲就是,在一个排序中,某些元素的存在依赖于另外的元素。或者说某些元素必须排在另外的元素后面。
比如说,穿衣服的时候,必须先穿裤衩,再穿秋裤,然后是棉裤和套在最外层的运动裤。而上身的背心和裤衩则没有依赖关系。
二、拓扑排序的实现
1.广度优先
简单来讲,就是始终把每次将入度为0的顶点去掉。
所以排序的结果就是[1,2,3,4,5]或者[1,2,4,3,5]。这个图就是有向无环图。
2.深度优先
从1开始,1->2->3->5或者1->2->4->5或者1->4->5
所以排序结果就是[1,2,3,4,5]或者[1,2,4,3,5]。这个图是一个有向无环图。
三、leetcode 207.课程表与拓扑排序
1.典型的拓扑排序题。因为如果要学习B课程,就必须要先学习A课程。
按广度优先来做:
2.建立一个邻接矩阵、一个入度表和一个队列。邻接矩阵的建立方法:二维的动态数组。数组的行是起始顶点,数组的列是到达顶点。入度表就按技术排序的方法。
3.如果一个数字的入度为0,就把它存到队列中。之后把队列中的数出队,同时将原数组长度-1,自然也将该数字的邻接数的入度-1。
4.如果此时邻接数有入度为0的,就继续放入队列,然后循环执行第三步,直到队列中为空。
5.此时,如果数组长度没有减到0,说明有入度不为0的数,意味着是图是有环的。如果数组长度减到0了,说明没有环,可以按照一定的顺序将数组中的数全部遍历完。
6.代码如下:
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
int[] indegress = new int[numCourses];
List<List<Integer>> adjency = new ArrayList<>();
Queue<Integer> queue = new LinkedList<>();
for(int i=0;i<numCourses;i++){
adjency.add(new ArrayList<>());
}
for(int[] cp:prerequisites){
indegress[cp[0]]++;
adjency.get(cp[1]).add(cp[0]);
}
for(int i=0;i<numCourses;i++){
if(indegress[i]==0)queue.offer(i);
}
while(!queue.isEmpty()){
int pre = queue.poll();
numCourses--;
for(int cur:adjency.get(pre))
if(--indegress[cur] == 0) queue.add(cur);
}
return numCourses==0;
}
}