圖 —— 拓撲排序

當每個任務有前後置關係時,需要找到一種滿足前後置關係的路線,將任務完成。

如果將每個任務看成一個節點,任務之間的前後置關係表示爲有向圖時,這種路線順序叫做爲圖進行拓撲排序。也叫關鍵路徑分析。

這裏的圖用鄰接矩陣法表示,算法的關鍵是:

  1. 找到一個沒有後繼的頂點 ;
  2. 在圖中刪除它,放入結果數組中 ;
  3. 重複 步驟 1 ,步驟 2 直到圖中沒有多餘的節點;

代碼:

/**
 * @ClassName Node
 * @Description 圖節點
 * @Author lzq
 * @Date 2019/6/19 04:39
 * @Version 1.0
 **/
public class Node {
    public char label;  //存放的數據
    public boolean wasVisited;  //記錄有無被訪問過

    public Node(char label) {
        this.label = label;
        this.wasVisited = false;
    }
}
/**
 * @ClassName Graph3
 * @Description 拓撲排序
 * @Author lzq
 * @Date 2019/6/19 06:49
 * @Version 1.0
 **/
public class Graph3 {
    private final int MAX_VERTS = 20;  //表示一個圖節點能連接的最大定點數
    private Node[] nodeList;  //頂點數組
    private int[][] adjMat; //鄰接矩陣,用來存方節點之間關係的
    private int nNode;  //當前頂點數量
    private char[] sorteArray;  //存放拓撲排序之後字符數組

    public Graph3() {
        nodeList = new Node[MAX_VERTS];
        adjMat = new int[MAX_VERTS][MAX_VERTS];
        nNode = 0;
        for (int i = 0; i < MAX_VERTS; i++) {
            for (int j = 0; j < MAX_VERTS; j++) {
                adjMat[i][j] = 0;
            }
        }
       sorteArray = new char[MAX_VERTS];
    }

    /**
     * 添加節點
     * @param lab
     */
    public void addNode(char lab) {
        nodeList[nNode++] = new Node(lab);
    }

    /**
     * 添加邊
     * @param start
     * @param end
     */
    public void addEdge(int start,int end) {
        adjMat[start][end] = 1;
    }

   /* *//**
     * 打印頂點
     * @param v
     *//*
    public void show(int v) {
        System.out.print(nodeList[v].label+"\t");
    }*/

    /**
     * 拓撲排序
     */
    public void topo() {
        int o = nNode;
        while (nNode > 0) {  //把所有頂點從圖裏面刪除
            int c = noSuccessors();
            if(c == -1) {  //找不到沒有後繼頂點的頂點
                System.out.println("錯誤!!!");
                return;
            }
            sorteArray[nNode-1] = nodeList[c].label;
            deleteNode(c);  //從圖中刪除當前頂點
        }

        System.out.print("拓撲排序:");
        for (int i = 0; i < o; i++) {
            System.out.print(sorteArray[i]);
        }
    }

    private void deleteNode(int del) {
        if(del != nNode-1){   //要刪除的頂點不是最後一個,就要處理鄰接矩陣
            for (int i = del; i < nNode-1; i++) {  //刪除頂點後面元素向前移動
                nodeList[i] = nodeList[i+1];
            }

            for (int i = del; i < nNode-1; i++) { //把鄰接矩陣中,刪除後面的行向上移動
                moveRowUp(i,nNode);
            }

            for (int col = del; col < nNode-1; col++) {
                moveColLeft(col,nNode-1);
            }
        }
        nNode--; //數量遞減
    }

    /**
     * 矩陣行向上移
     * @param row
     * @param length
     */
    private void moveRowUp(int row,int length) {
        for (int i = 0; i < length; i++) {
            adjMat[row][i] = adjMat[row+1][i];
        }
    }

    /**
     * 列往左移
     * @param col
     * @param length
     */
    private void moveColLeft(int col,int length) {
        for (int row = 0; row < length; row++) {
            adjMat[row][col] = adjMat[row][col+1];
        }
    }

    /**
     * 查找途中沒有後繼頂點的頂點
     * @return
     */
    private int noSuccessors() {
        boolean flag = true;
        for (int i = 0; i < nNode; i++) {
            flag = false;
            for (int j = 0; j < nNode; j++) {
                if (adjMat[i][j] > 0) {
                    flag = true;
                    break;
                }
            }
            if(!flag) {
                return i;
            }
        }
        return -1;
    }
}
/**
 * @ClassName TestDemo1
 * @Description 拓撲排序測試
 * @Author lzq
 * @Date 2019/6/19 07:21
 * @Version 1.0
 **/
public class TestDemo1 {
    public static void main(String[] args) {
        Graph3 graph3 = new Graph3();
        graph3.addNode('A');
        graph3.addNode('B');
        graph3.addNode('C');
        graph3.addNode('D');
        graph3.addNode('E');
        graph3.addNode('F');
        graph3.addNode('G');
        graph3.addNode('H');

        graph3.addEdge(0,3);
        graph3.addEdge(0,4);
        graph3.addEdge(1,4);
        graph3.addEdge(2,5);
        graph3.addEdge(3,6);
        graph3.addEdge(4,6);
        graph3.addEdge(5,7);
        graph3.addEdge(6,7);

        graph3.topo();
    }
}

測試代碼表示的圖:
在這裏插入圖片描述
運行結果:

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