0
点赞
收藏
分享

微信扫一扫

数据结构:拓扑排序、关键路径

王老师说 2022-03-11 阅读 66
数据结构

拓扑排序

//邻接表无权的有向图
public class Graph<V> {
    class Vertex<V> {//内部类,存储顶点的信息
        int in;//入度
        V date;//顶点值
        LinkedList<Integer> adj;//顶点的每一个邻接顶点构成的邻接表,Integer为顶点在顶点数组中的下标


        //顶点的构造方法
        Vertex(V date) {
            this.date = date;
            adj = new LinkedList<Integer>();
            in = 0;
        }
    }

    Vertex<V>[] vertexList;//由顶点组成的数组
    int numOfVertex;//顶点的数量
    int numOfEdge;//边的数量
    int size;//顶点的最大规模

    Graph() {
    }

    Graph(int size) {
        vertexList = new Vertex[size];
        numOfVertex = 0;
        numOfEdge = 0;
    }

    public void addVertex(V v) {
        vertexList[numOfVertex] = new Vertex<V>(v);
        numOfVertex++;
    }

    public void addEdge(int from, int to) {
        //传入的是一个Vertex对象在数组中的索引
        //根据顶点值找这个Vertex对象在数组中的索引
        vertexList[from].adj.add(to);
        numOfEdge++;
    }

    public void print() {
        for (Vertex v : vertexList) {
            System.out.println(v.in + "---" + v.date + "---" + v.adj);
        }
    }

    public void setIn() {//求入度
        for (int x = 0; x < numOfVertex; x++) {
            for (int i = 0; i < numOfVertex; i++) {
                for (int j = 0; j < vertexList[i].adj.size(); j++) {
                    if (vertexList[i].adj.get(j) == x) {
                        vertexList[x].in++;
                    }
                }
            }
        }
    }

    //拓扑排序
    public void topologicalSort() {
        Stack<Vertex<V>> stack = new Stack<>();
        //将入度为0的顶点入栈
        for (int i = 0; i < numOfVertex; i++) {
            if (vertexList[i].in == 0) {
                stack.push(vertexList[i]);
            }
        }
        int count = 0;//统计出栈的顶点个数
        while (!stack.empty()) {
            Vertex<V> temp = stack.pop();//出栈并返回出栈的顶点
            System.out.println(temp.date);//打印出栈的顶点
            count++;
            //把出栈的顶点指向的顶点的入度-1(即在图中删除这个顶点)
            for (int index : temp.adj) {
                vertexList[index].in--;
                if (vertexList[index].in == 0) {
                    stack.push(vertexList[index]);
                }
            }
        }
        if (count < numOfVertex) {
            System.out.println("存在环");
        } else {
            System.out.println("打印完毕");
        }
    }
}



public class GraphDemo {
    public static void main(String[] args) {
        Graph<String> graph = new Graph<String>(14);

        //添加顶点
        graph.addVertex("v0");
        graph.addVertex("v1");
        graph.addVertex("v2");
        graph.addVertex("v3");
        graph.addVertex("v4");
        graph.addVertex("v5");
        graph.addVertex("v6");
        graph.addVertex("v7");
        graph.addVertex("v8");
        graph.addVertex("v9");
        graph.addVertex("v10");
        graph.addVertex("v11");
        graph.addVertex("v12");
        graph.addVertex("v13");

        //添加边
        graph.addEdge(0, 11);
        graph.addEdge(0, 5);
        graph.addEdge(0, 4);
        graph.addEdge(1, 8);
        graph.addEdge(1, 4);
        graph.addEdge(1, 2);
        graph.addEdge(2, 9);
        graph.addEdge(2, 6);
        graph.addEdge(2, 5);
        graph.addEdge(3, 13);
        graph.addEdge(3, 2);
        graph.addEdge(4, 7);
        graph.addEdge(5, 12);
        graph.addEdge(5, 8);
        graph.addEdge(6, 5);
        graph.addEdge(8, 7);
        graph.addEdge(9, 11);
        graph.addEdge(9, 10);
        graph.addEdge(10, 13);
        graph.addEdge(12, 9);

        graph.setIn();
        graph.print();
        //拓扑排序
        graph.topologicalSort();

    }
}

关键路径

//邻接表带权的有向图
public class Graph<V> {
    class Vertex<V> {//内部类,存储顶点的信息
        int in;//入度
        V date;//顶点值
        HashMap<Integer, Integer> adj;//邻接表,顶点+弧的权值

        //顶点的构造方法
        Vertex(V date) {
            this.date = date;
            adj = new HashMap<Integer, Integer>();
            in = 0;
        }
    }

    Vertex<V>[] vertexList;//由顶点组成的数组
    int numOfVertex;//顶点的数量
    int numOfEdge;//边的数量
    int size;//顶点的最大规模

    Graph() {
    }

    Graph(int size) {
        vertexList = new Vertex[size];
        numOfVertex = 0;
        numOfEdge = 0;
    }

    public void addVertex(V v) {
        vertexList[numOfVertex] = new Vertex<V>(v);
        numOfVertex++;
    }

    public void addEdge(int from, int to, int weight) {
        //传入的是一个Vertex对象在数组中的索引
        //根据顶点值找这个Vertex对象在数组中的索引
        vertexList[from].adj.put(to, weight);
        numOfEdge++;
    }

    public void print() {
        for (Vertex v : vertexList) {
            System.out.println(v.in + "---" + v.date + "---" + v.adj);
        }
    }

    public void setIn() {//求入度
        for (int x = 0; x < numOfVertex; x++) {
            for (int i = 0; i < numOfVertex; i++) {//遍历所有顶点的邻接表
                Set<Integer> set = vertexList[i].adj.keySet();//拿到邻接表的所有键的集合
                for (Integer integer : set) {
                    if (integer == x) {
                        vertexList[x].in++;
                    }
                }
            }
        }
    }

    //根据date找索引
    public int getIndex(V v) {
        int i;
        for (i = 0; i < numOfVertex; i++) {
            if (vertexList[i].date == v) {
                break;
            }
        }
        return i;
    }

    //关键路径
    public void topologicalSort() {
        int[] etv = new int[numOfVertex];//事件(顶点)的最早发生时间数组
        int[] ltv = new int[numOfVertex];//事件(顶点)的最晚发生时间数组

        //第一步:求事件(顶点)的最早发生时间数组和拓扑序列
        Stack<Vertex<V>> stack = new Stack<>();
        Stack<Vertex<V>> stack2 = new Stack<>();//拓扑序列
        //将入度为0的顶点入栈
        for (int i = 0; i < numOfVertex; i++) {
            if (vertexList[i].in == 0) {
                stack.push(vertexList[i]);
            }
        }
        int count = 0;//计数
        while (!stack.empty()) {
            Vertex<V> temp = stack.pop();//出栈并返回出栈的顶点
            stack2.push(temp);//把出栈的顶点加入到拓扑序列
            count++;//出栈的元素数量
            //遍历栈顶元素的邻接表
            for (int index : temp.adj.keySet()) {
                vertexList[index].in--;     //把栈顶元素指向的顶点的入度-1(即在图中删除栈顶元素)
                if (vertexList[index].in == 0) {
                    stack.push(vertexList[index]);
                }
                etv[index] = Math.max(etv[index], etv[getIndex(temp.date)] + temp.adj.get(index));
                //Math.max(指向的元素 : 当前元素 + 当前元素到指向元素的权值)
            }
        }
//        if (count < numOfVertex) {
//            System.out.println("存在环");
//        } else {
//            //打印拓扑序列
//            for (Vertex vertex : stack2) {
//                System.out.println(vertex.date);
//            }
//        }
//        System.out.println(Arrays.toString(etv));

        //第二步:求事件(顶点)的最晚发生时间数组
        for (int i = 0; i < numOfVertex; i++) {
            ltv[i] = etv[numOfVertex - 1];
        }//初始化最晚发生时间数组
        int point = numOfVertex - 1;
        while (point>=0) {
            Vertex<V> temp = stack2.get(point);
            point--;
            for (int index : temp.adj.keySet()) {
                ltv[getIndex(temp.date)] = Math.min(ltv[getIndex(temp.date)], ltv[index] - temp.adj.get(index));
                // Math.min(当前元素 : 指向的元素 - 当前元素到指向元素的权值)
            }
        }
//        System.out.println(Arrays.toString(ltv));

        //第三步:求出关键路径
        int i = getIndex(stack2.get(0).date);//栈底元素的下标
        while (i != numOfVertex - 1) {
            Set<Integer> set = vertexList[i].adj.keySet();//拿到邻接表的所有键的集合
            for (int index : set) {
                if (etv[index] == ltv[index]) {
                    System.out.println("(" + vertexList[i].date + "," + vertexList[index].date
                            + ")" + vertexList[i].adj.get(index));
                    i = index;
                }
            }
        }
    }
}


public class GraphDemo {
    public static void main(String[] args) {
        Graph<String> graph = new Graph<String>(10);

        //添加顶点
        graph.addVertex("v0");
        graph.addVertex("v1");
        graph.addVertex("v2");
        graph.addVertex("v3");
        graph.addVertex("v4");
        graph.addVertex("v5");
        graph.addVertex("v6");
        graph.addVertex("v7");
        graph.addVertex("v8");
        graph.addVertex("v9");

        //添加边
        graph.addEdge(0, 2,4);
        graph.addEdge(0, 1,3);
        graph.addEdge(1, 4,6);
        graph.addEdge(1, 3,5);
        graph.addEdge(2, 5,7);
        graph.addEdge(2, 3,8);
        graph.addEdge(3, 4,3);
        graph.addEdge(4, 7,4);
        graph.addEdge(4, 6,9);
        graph.addEdge(5, 7,6);
        graph.addEdge(6, 9,2);
        graph.addEdge(7, 8,5);
        graph.addEdge(8, 9,3);

        graph.setIn();
//        graph.print();

        graph.topologicalSort();

    }
}
举报

相关推荐

0 条评论