一、概念
我们再说拓扑排序时,我们首先了解下?DAG
?
将有向无环图G=(V,E)中的所有顶点排成一个线性序列,使图中任意一对顶点u,v,之间不存在环路
DAG是一种特殊的有向图,它由一组顶点和一组有向边组成,且不存在任何环路。
- 每个顶点表示一个任务或操作,而有向边表示任务之间的依赖关系。
- 在有向无环图中,从任意顶点出发沿着有向边行走,不会回到起始顶点。
拓扑排序:
看完上面,我们说下拓扑排序,这玩意儿的出现就是针对有向无环图,通过此算法,找出邮箱无环图的序列
注意: 拓扑排序的序列是不唯一的
算法描述:
使用邻接矩阵的代码如下: 【不懂,就画图,每个新序列按照一步步去拆解】
/**
* @param1: 邻接矩阵,adjMatrix[i][j] = 0 表示节点 i 和 j 之间没有边直接相连
* @return: 拓扑序列
* @description: 对用邻接表 adjMatrix 表示的图进行拓扑排序
*/
public static int[] tuopuSort(int[][] adjMatrix){
//n表示图中的节点数
int n=adjMatrix.length;
//计算图中每个节点的入度,inDegree[i]=j 表示节点i 的入度为j
int[] inDegree=new int[n];
for(int j=0;j<n;j++){
for(int i=0;i<n;i++){
if(adjMatrix[i][j]!=0){
inDegree[j]++;
}
}
}
//将入度为0的节点加入到队列中
Queue<Integer> queue=new LinkedList<>();
for(int i=0;i<n;i++){
if(inDegree[i]==0){
queue.offer(i);
}
}
//记录拓扑序列
int[] order=new int[n];
//记录遍历节点的顺序
int cnt=0;
//通过BFS算法完成拓扑序列
while(!queue.isEmpty()){
//取出队首节点
int cur=queue.poll();
//取出节点的顺序即为拓扑排序的结果
order[cnt]=cnr;
cnt++;
//遍历当前节点cur所指向的所有节点
for(int next=0;next<n;next++){
if(adjMatrix[cur][next]!=0){
//去掉cur指向next的边,故next的入度减1
inDegree[next]--;
//将入度为0的节点再次加入队列
if(inDegree[next]==0){
queue.offer(next);
}
}
}
}
if(cnt!=n){
//图中存在环,拓扑排序不存在
return new int[]{};
}else{
return order;
}
}
使用邻接表
/**
* @param1: 邻接表,adjList[i] 中存储节点 i 指向的节点
* @param2: 图的节点数
* @return: 拓扑序列
* @description: 对用邻接表 adjList 表示的图进行拓扑排序
*/
public static int[] tuopuSort(List<Integer>[] adjList,int n){
//计算图中每个节点的入度,inDegree[i]=j表示节点i的入度为j
int[] inDegree=new int[n];
for(List<Integer> list:adjList){
for(Integer node: list){
inDegree[node]++;
}
}
//将入度为0的节点加入到队列中
Queue<Integer> queue=new LinkedList<>();
for(int i=0;i<n;i++){
if(inDegree[i]==0){
queue.offer(i);
}
}
//记录拓扑排序
if(cnt!=n){
//图中存在环,拓扑排序不存在
return new int[]{};
}else{
return order;
}
}