拓撲排序的算法實現

一、定義

對一個有向無環圖(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();
    }
}

 

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