算法 --- 拓扑排序的Java实现

醉酒当歌 提交于 2020-02-13 21:49:14

在一个有向无回路图(AOV网,Activity On Vertex)中找到一个拓扑序列的过程称为拓扑排序。

拓扑序列:图中所有顶点沿着水平线排列而成的一个序列。

拓扑排序的实现步骤:1>从有向图中选择一个没有前驱(即入度为0)的顶点并且输出它;

                                    2>从图中删除该结点,并且删除所有从该结点出发的弧,将这些弧头的入度减1;

                                    3> 重复上述两步,直到所有的顶点都输出。
源码:

public class Test {

    /** 图的顶点信息*/
    private static char[] vertexs = {'A','B','C','D','E','F'};
    /** 图的顶点的使用情况 */
    private static int[] vertexStatus = {0,0,0,0,0,0};
    /** 使用邻接矩阵存储图的边信息*/
    private static int[][] edges = {
            {0,1,1,1,0,0},
            {0,0,0,0,0,0},
            {0,1,0,0,1,0},
            {0,0,0,0,1,1},
            {0,0,0,0,0,0},
            {0,0,0,0,1,0}
    };

    class Stack {
        private int[] stackList;
        private int top;
        public Stack(int length) {
            stackList = new int[length];
            top = -1;
        }

        /** 入栈 */
        public void push(int val) {
            stackList[++top] = val;
        }
        /** 出栈 */
        public void pop() {
            --top;
        }
        /** 查询栈顶元素 */
        public int peek() {
            if (top != -1) {
                return stackList[top];
            }
            return -1;
        }
        /** 判空 */
        public boolean isEmpty() {
            if (top == -1) {
                return true;
            }
            return false;
        }
    }

    public static void main(String[] args) throws Exception {
        /**
         * 拓扑排序的实现
         * 1.获取入度为0的节点
         * 2.将入度为0的节点保存到结果列表中,查找有向图中以该节点为首的边所对应的尾节点的入度减1
         * 3.重复1,2
         */
        int index = getInDegreeIndex();
        if (index != -1) {
            char[] results = new char[vertexs.length];
            int resultIndex = 0;
            results[resultIndex] = vertexs[index];
            Test.Stack stack = new Test().new Stack(vertexs.length);
            stack.push(index);
            while(!stack.isEmpty()) {
                updateInDegree(stack.peek());
                vertexStatus[stack.peek()] = 1;
                stack.pop();
                index = getInDegreeIndex();
                if (index != -1) {
                    stack.push(index);
                    results[++resultIndex] = vertexs[index];
                }
            }
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < results.length; i++) {
                sb.append(results[i]);
                if (i != results.length - 1) {
                    sb.append(",");
                }
            }
            System.out.println(sb);
        } else {
            System.out.println("该图存在环,不能进行拓扑排序!");
        }

    }

    /** 获取入度为0的结点下标索引*/
    private static int getInDegreeIndex () {
        int index = -1;
        int row = edges.length;
        int col = edges[0].length;
        for (int i = 0; i < col;i++) {
            if (vertexStatus[i] == 0) {
                for (int j = 0; j < row; j++) {
                    index = i;
                    if (edges[j][i] != 0) {
                        index = -1;
                        break;
                    }
                }
                if (index != -1) {
                    return index;
                }
            }
        }
        return index;
    }

    /** 入度减1操作*/
    private static void updateInDegree (int index) {
        int col = edges.length;
        for (int i = 0; i < col;i++) {
            if (edges[index][i] != 0) {
                edges[index][i]--;
            }
        }
    }
}

运行结果:A,C,B,D,F,E

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!