拓扑排序的算法实现

一、定义

对一个有向无环图(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();
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章