一、定义
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
二、DFS算法
找出一个入度为 0 的顶点,通过递归的方式遍历它所有可达的顶点,将其输出到拓扑排序的结果序列中,对遍历过的顶点做标记,避免其被重复访问。循环执行上面的过程,直到所有的顶点都被输出。
1.基于邻接表实现
public class TopologicalSort_AdjacencyList_Dfs {
private int mVertexNum; // 顶点数
private int[] mInDegree; // 顶点入度数
private List<Integer> mAdjacencyList[]; // 邻接表
private boolean[] isVisited; // 用来避免顶点被重复访问
private Stack<Integer> mReversePost; // 用栈来保存排序结果
public TopologicalSort_AdjacencyList_Dfs(int vertexNum) {
this.mVertexNum = vertexNum;
this.mInDegree = new int[vertexNum];
this.mAdjacencyList = new LinkedList[vertexNum];
for (int i = 0; i < vertexNum; ++i) {
mAdjacencyList[i] = new LinkedList<>();
}
this.isVisited = new boolean[vertexNum];
this.mReversePost = new Stack<>();
}
/**
* 添加图的边,累计终止顶点入度
*
* @param s 起始顶点
* @param t 终止顶点
*/
public void addEdge(int s, int t) {
mAdjacencyList[s].add(t);
mInDegree[t]++;
}
/**
* 拓扑排序
*/
public void sort() {
for (int i = 0; i < mVertexNum; i++) {
if (mInDegree[i] == 0) {
recurDfs(i);
}
}
System.out.println(mReversePost);
}
/**
* 递归方法
*
* @param s
*/
private void recurDfs(int s) {
if (isVisited[s] || mReversePost.size() == mVertexNum) {
return;
}
isVisited[s] = true;
mReversePost.push(s);
for (int i = 0; i < mAdjacencyList[s].size(); i++) {
int w = mAdjacencyList[s].get(i);
if (isVisited[w]) {
return;
}
mInDegree[w]--;
if (mInDegree[w] == 0) {
recurDfs(w);
}
}
}
public static void main(String[] args) {
TopologicalSort_AdjacencyList_Dfs graph = new TopologicalSort_AdjacencyList_Dfs(8);
graph.addEdge(0, 1);
graph.addEdge(0, 3);
// graph.addEdge(1, 2);
graph.addEdge(1, 4);
graph.addEdge(2, 5);
graph.addEdge(4, 5);
graph.addEdge(4, 6);
graph.addEdge(5, 7);
graph.addEdge(6, 7);
graph.sort();
}
}
2.基于邻接矩阵实现
public class TopologicalSort_AdjacencyMatrix_Dfs {
private int mVertexNum; // 顶点数
private int[] mInDegree; // 顶点入度数
private int[][] mAdjacencyMatrix; // 邻接矩阵
private boolean[] isVisited; // 用来避免顶点被重复访问
private Stack<Integer> mReversePost; // 用栈来保存排序结果
public TopologicalSort_AdjacencyMatrix_Dfs(int vertexNum) {
this.mVertexNum = vertexNum;
this.mInDegree = new int[vertexNum];
this.mAdjacencyMatrix = new int[vertexNum][vertexNum];
for (int i = 0; i < vertexNum; i++) {
for (int j = 0; j < vertexNum; j++) {
mAdjacencyMatrix[i][j] = 0;
}
}
this.isVisited = new boolean[vertexNum];
this.mReversePost = new Stack<>();
}
/**
* 添加图的边,累计终止顶点入度
*
* @param s 起始顶点
* @param t 终止顶点
*/
public void addEdge(int s, int t) {
mAdjacencyMatrix[s][t] = 1;
mInDegree[t]++;
}
/**
* 拓扑排序
*/
public void sort() {
for (int i = 0; i < mVertexNum; i++) {
if (mInDegree[i] == 0) {
recurDfs(i);
}
}
System.out.println(mReversePost);
}
/**
* 递归方法
*
* @param s
*/
private void recurDfs(int s) {
if (isVisited[s] || mReversePost.size() == mVertexNum) {
return;
}
isVisited[s] = true;
mReversePost.push(s);
for (int i = 0; i < mVertexNum; i++) {
if (mAdjacencyMatrix[s][i] == 1 && !isVisited[i]) {
mInDegree[i]--;
if (mInDegree[i] == 0) {
recurDfs(i);
}
}
}
}
public static void main(String[] args) {
TopologicalSort_AdjacencyMatrix_Dfs graph = new TopologicalSort_AdjacencyMatrix_Dfs(8);
graph.addEdge(0, 1);
graph.addEdge(0, 3);
// graph.addEdge(1, 2);
graph.addEdge(1, 4);
graph.addEdge(2, 5);
graph.addEdge(4, 5);
graph.addEdge(4, 6);
graph.addEdge(5, 7);
graph.addEdge(6, 7);
graph.sort();
}
}
三、Kahn算法
找出一个入度为 0 的顶点,将其输出到拓扑排序的结果序列中,并且把这个顶点从图中删除。循环执行上面的过程,直到所有的顶点都被输出。
1.基于邻接表实现
public class TopologicalSort_AdjacencyList_Kahn {
private int mVertexNum; // 顶点数
private int[] mInDegree; // 顶点入度数
private List<Integer> mAdjacencyList[]; // 邻接表
private Deque<Integer> mZeroDegreeDeque; // 入度数为0的顶点
public TopologicalSort_AdjacencyList_Kahn(int vertexNum) {
this.mVertexNum = vertexNum;
this.mInDegree = new int[vertexNum];
this.mAdjacencyList = new LinkedList[vertexNum];
for (int i = 0; i < vertexNum; ++i) {
mAdjacencyList[i] = new LinkedList<>();
}
this.mZeroDegreeDeque = new ArrayDeque<>();
}
/**
* 添加图的边,累计终止顶点入度
*
* @param s 起始顶点
* @param t 终止顶点
*/
public void addEdge(int s, int t) {
mAdjacencyList[s].add(t);
mInDegree[t]++;
}
/**
* 拓扑排序
*/
public void sort() {
for (int i = 0; i < mVertexNum; i++) {
if (mInDegree[i] == 0) {
mZeroDegreeDeque.offer(i);
}
}
List<Integer> result = new ArrayList<>();
while (!mZeroDegreeDeque.isEmpty()) {
int s = mZeroDegreeDeque.poll();
for (int j = 0; j < mAdjacencyList[s].size(); j++) {
int w = mAdjacencyList[s].get(j);
mInDegree[w]--;
if (mInDegree[w] == 0) {
mZeroDegreeDeque.offer(w);
}
}
result.add(s);
}
System.out.println(result);
}
public static void main(String[] args) {
TopologicalSort_AdjacencyList_Kahn graph = new TopologicalSort_AdjacencyList_Kahn(8);
graph.addEdge(0, 1);
graph.addEdge(0, 3);
graph.addEdge(1, 2);
graph.addEdge(1, 4);
graph.addEdge(2, 5);
graph.addEdge(4, 5);
graph.addEdge(4, 6);
graph.addEdge(5, 7);
graph.addEdge(6, 7);
graph.sort();
}
}
2.基于邻接矩阵实现
public class TopologicalSort_AdjacencyMatrix_Kahn {
private int mVertexNum; // 顶点数
private int[] mInDegree; // 顶点入度数
private int[][] mAdjacencyMatrix; // 邻接矩阵
private Deque<Integer> mZeroDegreeDeque; // 入度数为0的顶点
public TopologicalSort_AdjacencyMatrix_Kahn(int vertexNum) {
this.mVertexNum = vertexNum;
this.mInDegree = new int[vertexNum];
this.mAdjacencyMatrix = new int[vertexNum][vertexNum];
for (int i = 0; i < vertexNum; i++) {
for (int j = 0; j < vertexNum; j++) {
mAdjacencyMatrix[i][j] = 0;
}
}
this.mZeroDegreeDeque = new ArrayDeque<>();
}
/**
* 添加图的边,累计终止顶点入度
*
* @param s 起始顶点
* @param t 终止顶点
*/
public void addEdge(int s, int t) {
mAdjacencyMatrix[s][t] = 1;
mInDegree[t]++;
}
/**
* 拓扑排序
*/
public void sort() {
for (int i = 0; i < mVertexNum; i++) {
if (mInDegree[i] == 0) {
mZeroDegreeDeque.offer(i);
}
}
List<Integer> result = new ArrayList<>();
while (!mZeroDegreeDeque.isEmpty()) {
int s = mZeroDegreeDeque.poll();
for (int j = 0; j < mVertexNum; j++) {
if (mAdjacencyMatrix[s][j] != 1) {
continue;
}
mInDegree[j]--;
if (mInDegree[j] == 0) {
mZeroDegreeDeque.offer(j);
}
}
result.add(s);
}
System.out.println(result);
}
public static void main(String[] args) {
TopologicalSort_AdjacencyMatrix_Kahn graph = new TopologicalSort_AdjacencyMatrix_Kahn(8);
graph.addEdge(0, 1);
graph.addEdge(0, 3);
graph.addEdge(1, 2);
graph.addEdge(1, 4);
graph.addEdge(2, 5);
graph.addEdge(4, 5);
graph.addEdge(4, 6);
graph.addEdge(5, 7);
graph.addEdge(6, 7);
graph.sort();
}
}