解决拓扑排序之前要先认识什么是拓扑排序 :
对一个有向无环图(Directed Acyclic Graph简称DAG)图G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。
解决步骤:
- 使用邻接表将顶点联系起来,辅助数组inDegree表示每个顶点的入度。
- 借助队列和计数器变量来判断该有向图是否有环:
- 将入度为零的顶点入队(也就是拓扑图第一个顶点)
- 取队首,遍历与之相邻的顶点,若该顶点入度减一后为零就将其入队
- 只要队列非空就循环操作,计算器循环加一,与顶点数比较是否相等
- 本题末尾也不能输出空格,因此输出拓扑序列时要加限制条件
重要注释:
- list模拟邻接表
使用每个元素为一个list容器模拟邻接表进行建图
list[a]所对应的数组中存储着该顶点所指向的其他顶点
inDegree数组代表每一个顶点的入度情况
- 使用一个队列,初始时将所有入度为0的顶点全部入队,之后采用BFS的思想:
依次取出队头元素并存入结果数组中,然后在邻接表中遍历该队头元素所指向的其他顶点,将这些顶点的入度全部减一,若减一后某顶点的入度变为0,则将该顶点进行入队操作,重复此步骤直至队列为空为止。
- 设置一个用于判断图中是否存在环(是否可以得到拓扑序列)的计数器,在弹出队头元素后要将计数器加一,最后队列为空后,若计数器的值与顶点数相同,则说明图不存在环,可以得到拓扑序列。
import java.util.*; public class Main{ public static void main (String[] args){ Scanner sc = new Scanner(System.in); String[] str = sc.nextLine().split(" "); int n = Integer.parseInt(str[0]); Graph graph = new Graph(n); while(sc.hasNextLine()){ String[] line = sc.nextLine().split(" "); int u = Integer.parseInt(line[0]);//开始顶点、 int v = Integer.parseInt(line[1]); //入度加1 graph.inDegree[v-1]++; //u点增加出度(邻接链表) graph.list.get(u-1).add(v-1); } if(graph.topologincalSort()){ for(int num:graph.res){ System.out.print(num+" "); } }else System.out.println("-1"); } } class Graph{ public int[] inDegree; ArrayList<ArrayList<Integer>> list = new ArrayList<>(); public List<Integer> res = new ArrayList<>(); public Graph(int n){ inDegree = new int[n]; for(int i=0;i<n;i++) list.add(new ArrayList<>()); } public boolean topologincalSort(){ int num = 0; Stack<Integer> stack = new Stack<>(); for(int i = 0;i<inDegree.length;i++) if(inDegree[i] == 0) stack.push(i); while(!stack.isEmpty()){ int u = stack.pop(); res.add(u+1); int len = list.get(u).size(); for(int i=0;i<len;i++){ int v = list.get(u).get(i); inDegree[v]--; if(inDegree[v]==0) stack.push(v); } list.get(u).clear(); num++; } return num == inDegree.length; } }