图的应用-拓扑排序与关键路径(JAVA实现)

AOV与AOE

AOV网(用于解决拓扑排序):用节点表示活动,弧表示优先制约关系

  1. 若存在从节点 i 到节点 j 的路径,则 i 为 j 的前驱,j 为 i 的后继
  2. AOV网中不允许有回路,判断是否有回路的方法是,将AOV网中的所有节点进行拓扑排序形成有序序列,若存在<i,j>,则序列中节点 i 必然在节点 j 前

AOE网(用于解决关键路径):用弧表示活动,节点表示活动的开始和结束

拓扑排序(适用于十字链表法存储的有向图)

作用:用于判断有向图中是否有环,若无环,则若存在<i,j>,则拓扑序列中节点 i 必须在节点 j 前

代码实现:顺便复习一下十字链表和广度优先搜索

 /**
     * 十字链表
     *
     * 针对有向图
     */
    public static class AcrossLinkedList{
        //数组部分
        NodeElement[] elements = new NodeElement[12];

        /**
         * 用于描述节点
         */
        public static class NodeElement{
            //以该节点为出点的弧的链表的头节点
            EdgeElement outerEdgeElement;
            //以该节点为入点的边的链表的头节点
            EdgeElement innerEdgeElement;
            //该节点中存储的数据
            Object data;
            //记录是否被软删除
            boolean whetherRemove;

            public NodeElement(EdgeElement outerEdgeElement, EdgeElement innerEdgeElement, Object data, boolean whetherRemove) {
                this.outerEdgeElement = outerEdgeElement;
                this.innerEdgeElement = innerEdgeElement;
                this.data = data;
                this.whetherRemove = whetherRemove;
            }
        }

        /**
         * 用于描述边
         */
        public static class EdgeElement{
            //从哪个节点出
            NodeElement outerNode;
            //到哪个节点入
            NodeElement innerElement;
            //出链表中下一个边节点:即下一个出节点相同的边
            EdgeElement outerNextEdge;
            //入链表中下一个边节点:即下一个入节点相同的边
            EdgeElement innerNextEdge;
            //记录是否被软删除
            boolean whetherRemove;

            public EdgeElement(NodeElement outerNode, NodeElement innerElement, EdgeElement outerNextEdge, EdgeElement innerNextEdge, boolean whetherRemove) {
                this.outerNode = outerNode;
                this.innerElement = innerElement;
                this.outerNextEdge = outerNextEdge;
                this.innerNextEdge = innerNextEdge;
                this.whetherRemove = whetherRemove;
            }
        }

        public static void main(String[] args) {
            AcrossLinkedList acrossLinkedList = new AcrossLinkedList();
            NodeElement c1 = new NodeElement(null, null, "C1",false);
            NodeElement c2 = new NodeElement(null, null, "C2",false);
            NodeElement c3 = new NodeElement(null, null, "C3",false);
            NodeElement c4 = new NodeElement(null, null, "C4",false);
            NodeElement c5 = new NodeElement(null, null, "C5",false);
            NodeElement c6 = new NodeElement(null, null, "C6",false);
            NodeElement c7 = new NodeElement(null, null, "C7",false);
            NodeElement c8 = new NodeElement(null, null, "C8",false);
            NodeElement c9 = new NodeElement(null, null, "C9",false);
            NodeElement c10 = new NodeElement(null, null, "C10",false);
            NodeElement c11 = new NodeElement(null, null, "C11",false);
            NodeElement c12 = new NodeElement(null, null, "C12",false);


            EdgeElement c1_c4 = new EdgeElement(c1, c4, null, null,false);
            EdgeElement c1_c2 = new EdgeElement(c1, c2, c1_c4, null,false);
            EdgeElement c1_c3 = new EdgeElement(c1, c3, c1_c2, null,false);
            EdgeElement c1_c12 = new EdgeElement(c1, c12, c1_c3, null,false);
            EdgeElement c9_c12 = new EdgeElement(c9, c12, null, c1_c12,false);
            EdgeElement c9_c10 = new EdgeElement(c9, c10, c9_c12, null,false);
            EdgeElement c9_c11 = new EdgeElement(c9, c11, c9_c10, null,false);

            EdgeElement c4_c5 = new EdgeElement(c4, c5, null, null,false);
            EdgeElement c2_c3 = new EdgeElement(c2, c3, null, c1_c3,false);
            EdgeElement c10_c12 = new EdgeElement(c10, c12, null, c9_c12,false);
            EdgeElement c11_c6 = new EdgeElement(c11, c6, null, null,false);
            EdgeElement c3_c5 = new EdgeElement(c3, c5, null, c4_c5,false);
            EdgeElement c3_c7 = new EdgeElement(c3, c7, c3_c5, null,false);
            EdgeElement c3_c8 = new EdgeElement(c3, c8, c3_c7, null,false);
            EdgeElement c6_c8 = new EdgeElement(c6, c8, null, c3_c8,false);
            EdgeElement c5_c7 = new EdgeElement(c5, c7, null, c3_c7,false);

            c1.innerEdgeElement=null;
            c2.innerEdgeElement=c1_c2;
            c3.innerEdgeElement=c2_c3;
            c4.innerEdgeElement=c1_c4;
            c5.innerEdgeElement=c4_c5;
            c6.innerEdgeElement=c11_c6;
            c7.innerEdgeElement=c5_c7;
            c8.innerEdgeElement=c6_c8;
            c9.innerEdgeElement=null;
            c10.innerEdgeElement=c9_c10;
            c11.innerEdgeElement=c9_c11;
            c12.innerEdgeElement=c9_c12;

            c1.outerEdgeElement=c1_c12;
            c2.outerEdgeElement=c2_c3;
            c3.outerEdgeElement=c3_c8;
            c4.outerEdgeElement=c4_c5;
            c5.outerEdgeElement=c5_c7;
            c6.outerEdgeElement=c6_c8;
            c7.outerEdgeElement=null;
            c8.outerEdgeElement=null;
            c9.outerEdgeElement=c9_c11;
            c10.outerEdgeElement=c10_c12;
            c11.outerEdgeElement=c11_c6;
            c12.outerEdgeElement=null;

            acrossLinkedList.elements[0] = c1;
            acrossLinkedList.elements[1] = c2;
            acrossLinkedList.elements[2] = c3;
            acrossLinkedList.elements[3] = c4;
            acrossLinkedList.elements[4] = c5;
            acrossLinkedList.elements[5] = c6;
            acrossLinkedList.elements[6] = c7;
            acrossLinkedList.elements[7] = c8;
            acrossLinkedList.elements[8] = c9;
            acrossLinkedList.elements[9] = c10;
            acrossLinkedList.elements[10] = c11;
            acrossLinkedList.elements[11] = c12;

            System.out.println(acrossLinkedList.elements);

           // BFS(acrossLinkedList);
            //申请一个空序列,用于存放顶点
            List<NodeElement> nodeElements = new ArrayList<>();
            //当序列未包含所有顶点
            while (nodeElements.size()!=12){
                for (int i=0;i<acrossLinkedList.elements.length;i++){
                    NodeElement element = acrossLinkedList.elements[i];
                    //若节点已经被软删除,则越过
                    if (element.whetherRemove == true){
                        continue;
                    }
                    //若没有弧从该顶点进来,则将该顶点加入序列,且删除图中该顶点以及从该顶点出去的弧
                    if (element.innerEdgeElement == null || element.innerEdgeElement.whetherRemove == true) {
                        //将节点加入节点序列
                        nodeElements.add(element);
                        //软删除该节点
                        element.whetherRemove=true;
                        //软删除从节点出去的弧
                        EdgeElement outerNextEdge = element.outerEdgeElement;
                        while (outerNextEdge!=null){
                            outerNextEdge.whetherRemove = true;
                            outerNextEdge = outerNextEdge.outerNextEdge;
                        }
                    }
                }
            }

            //打印拓扑排序结果
            for (NodeElement nodeElement : nodeElements) {
                System.out.println(nodeElement.data);
            }
        }

        /**
         * 顺便复习一下BFS
         * 1)申请一个存放所有节点状态的序列  2)申请一个空队列
         * 3)遍历所有节点,先将A节点入队列
         * 4)若队列不为空,则弹出队列中元素,访问,当存在从该节点出去的边,则将令一端点加入队列
         * 5)循环步骤4,直到所有节点均被访问为止
         */
        public static void BFS(AcrossLinkedList acrossLinkedList){
            //申请一个节点被访问状态序列
            Map<String,Boolean> visited = new HashMap<>(4);
            visited.put("A",false);
            visited.put("B",false);
            visited.put("C",false);
            visited.put("D",false);
            //申请一个存放待处理节点的队列
            Queue<NodeElement> assistanceQueue = new LinkedList<>();
            //循环直到所有节点访问状态均为true为止
            for (NodeElement element : acrossLinkedList.elements) {
                assistanceQueue.offer(element);
                while (!assistanceQueue.isEmpty()){ //当队列不为空
                    //顺序弹出队列中的节点
                    NodeElement poll = assistanceQueue.poll();
                    //若已经访问过,则跳过
                    if (visited.get(poll.data)){
                        continue;
                    }
                    System.out.println(poll.data); // 输出
                    visited.put(poll.data.toString(),true);//将访问状态改为true
                    EdgeElement edge = poll.outerEdgeElement;
                    while (edge!=null){
                        //将边的另一头入队
                        assistanceQueue.offer(edge.innerElement);
                        edge = edge.outerNextEdge;
                    }
                }
            }
        }
    }

关键路径

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值