图(1)

:表示多对多的关系

包含: 一组顶点V      表示顶点的集合,一组边E   表示边的集合 

(v,w)无向边   <v,w> 有向边

三要素:  1.图,2.G(V,E)是由一个非空的有限顶点集合V一个有限边集合E组成   必须有一个顶点    3.操作集

常见术语:所有边无方向的  是无向图     有向的  有向图

 

怎么在程序中表示一个图?

1.邻接矩阵G[N][N]-------N个顶点从0到N-1编号   G[i][[j]={1(v),0(e)}

特点  1.对角线 为0  2. 这个图是对称的 

对于无向图的存储,怎样可以节省一般的空间?

用一个长度为N(N+1)/2的1维数组A存储(G00,G10,G11,Gn-1n-1),改变后它的下标是(i*(i+1)/2+j)

对于网络的将G[i][j]的值定义为边<vi,vj>的权重即可

行 表示出度 列 表示入度

邻接表   一定要足够稀疏

 

深度优先搜索DFS

DFS  对应 先序遍历  

BFS 对应 层序遍历  

public interface Graph {
    public static final int UndirectedGraph=0;  // 无向图
    public static final int DirectedGraph=1;  // 有向图
    //返回图的类型1
     public int getType();
     //返回图的顶点数2
    public int getVexNum();
    //返回图的边数3
    public int getEdgeNum();
    //返回图的所有顶点4
    public Iterator getVertex();
    //返回图的所有边5
    public Iterator getEdge();
    //删除一个顶点6
    public void remove(Vertex vertex);
    //删除一条边7
    public void remove(Edge edge);
    //添加一个顶点8
    public Node insert(Vertex vertex);
    //添加一条边9
    public Node insert(Edge edge);
    // 判断顶点u,v是否邻接,是否有边从u到v10
    public boolean areAdjacent(Vertex u,Vertex v);
    //返回从u指向v的边,不存在即返回null 11
    public Edge edgeFromTo(Vertex u,Vertex v);
    //返回从u出发可以直接到达的邻接顶点 12
    public Iterator adjVertexs(Vertex u);
    //对图进行深度优先遍历 13
    public Iterator DFSTraverse(Vertex v);
    //对图进行广度优先遍历 14
    public Iterator BFSTraverse(Vertex v);
    //求顶点V到其他顶点的最短路径15
    public  Iterator shortestPath(Vertex v);
    //求无向图的最小生成树,如果是有向图无此操作
    public void generateMST() throws UnsupportedOperation;
    //求有向图的拓扑排序
    public Iterator toplogicalSort() throws UnsupportedOperation;
    //求有向无环图的关键路径
    public void criticalPath() throws  UnsupportedOperation;

}

UnsupportOperation

public class UnsupportedOperation extends RuntimeException{
    public UnsupportedOperation(String str){
        super(str);
    }
}
// 双链式存储结构的顶点定义
public class Vertex {

private Object info; //顶点信息
private LinkedList adjacentEdges; //顶点的邻接边表
private LinkedList reAdjacentEdges; //顶点的逆邻接边表,无向图时为空
private boolean visited; //访问状态
private Node vexPosition; //顶点在顶点表中的位置
private int graphType; //顶点所在图的类型
private Object application; //应用。如求最短路径时为 Path,求关键路径时为 Vtime

//构造方法:在图 G 中引入一个新顶点
public Vertex(Graph g, Object info) {
this.info = info;
adjacentEdges = new LinkedListDLNode();
reAdjacentEdges = new LinkedListDLNode();
visited = false;
graphType = g.getType();
vexPosition = g.insert(this);
application = null;
}

//辅助方法:判断顶点所在图的类型
private boolean isUnDiGraphNode(){ return graphType==Graph.UndirectedGraph;}

//获取或设置顶点信息
public Object getInfo(){ return info;}
public void setInfo(Object obj){ this.info = info;}

//与顶点的度相关的方法
public int getDeg(){
if (isUnDiGraphNode())
return adjacentEdges.getSize(); //无向图顶点的(出/入)度为邻接边表规模
else
return getOutDeg()+getInDeg(); //有向图顶点的度为出度与入度之和
}

public int getOutDeg(){
return adjacentEdges.getSize(); 	//有(无)向图顶点的出度为邻接表规模
}	

public int getInDeg(){	
if (isUnDiGraphNode())	
return adjacentEdges.getSize(); //无向图顶点的入度就是它的度	
else	
return reAdjacentEdges.getSize(); //有向图顶点入度为逆邻接表的规模	
}	

//获取与顶点关联的边	
public LinkedList getAdjacentEdges(){ return adjacentEdges;}	
public LinkedList getReAdjacentEdges(){	
if (isUnDiGraphNode())	
return adjacentEdges; //无向图顶点的逆邻接边表就是其邻接边表	
else	
return reAdjacentEdges;	
}


//取顶点在所属图顶点集中的位置
public Node getVexPosition(){ return vexPosition;}

//与顶点访问状态相关方法
public boolean isVisited(){ return visited;}
public void setToVisited(){ visited = true;}
public void setToUnvisited(){ visited = false;}

//取或设置顶点应用信息
protected Object getAppObj(){ return application;}
protected void setAppObj(Object app){ application = app;}

//重置顶点状态信息
public void resetStatus(){
visited = false;
application = null;
}
}

public class Edge {

public static final int NORMAL = 0;
public static final int MST = 1; //MST 边
public static final int CRITICAL = 2;//关键路径中的边
private int weight; //权值
private Object info; //边的信息
private Node edgePosition; //边在边表中的位置
private Node firstVexPosition; //边的第一顶点与第二顶点
private Node secondVexPosition; //在顶点表中的位置
private Node edgeFirstPosition; //边在第一(二)顶点的邻接(逆邻接)边表中的位置
private Node egdeSecondPosition;//在无向图中就是在两个顶点的邻接边表中的位置
private int type; //边的类型
private int graphType; //所在图的类型


//构造方法:在图 G 中引入一条新边,其顶点为 u、 v
public Edge(Graph g, Vertex u, Vertex v, Object info){
this(g,u,v,info,1);
}

public Edge(Graph g, Vertex u, Vertex v, Object info, int weight) {
this.info = info;
this.weight = weight;
edgePosition = g.insert(this);
firstVexPosition = u.getVexPosition();
secondVexPosition = v.getVexPosition();
type = Edge.NORMAL;
graphType = g.getType();

if (graphType==Graph.UndirectedGraph){
//如果是无向图,边应当加入其两个顶点的邻接边表
edgeFirstPosition = u.getAdjacentEdges().insertLast(this);
egdeSecondPosition = v.getAdjacentEdges().insertLast(this);
}else {
//如果是有向图,边加入起始点的邻接边表,终止点的逆邻接边表
edgeFirstPosition = u.getAdjacentEdges().insertLast(this);
egdeSecondPosition = v.getReAdjacentEdges().insertLast(this);
}

}

//get&set methods
public Object getInfo(){ return info;}
public void setInfo(Object obj){ this.info = info;}
public int getWeight(){ return weight;}
public void setWeight(int weight){ this.weight = weight;}
public Vertex getFirstVex(){ return (Vertex)firstVexPosition.getData();}

public Vertex getSecondVex(){ return (Vertex)secondVexPosition.getData();}
public Node getFirstVexPosition(){ return firstVexPosition;}
public Node getSecondVexPosition(){ return secondVexPosition;}
public Node getEdgeFirstPosition(){ return edgeFirstPosition;}
public Node getEdgeSecondPosition(){ return egdeSecondPosition;}
public Node getEdgePosition(){ return edgePosition;}
//与边的类型相关的方法
public void setToMST(){ type = Edge.MST;}
public void setToCritical(){ type = Edge.CRITICAL;}
public void resetType(){ type = Edge.NORMAL;}
public boolean isMSTEdge(){ return type==Edge.MST;}
public boolean isCritical(){ return type==Edge.CRITICAL;}
}

 

 

深度优先搜索(depth first search) 遍历类似于树的先根遍历,是树的先根遍历的推广。
深度优先搜索的基本方法是:从图中某个顶点发 v 出发,访问此顶点,然后依次从 v
的未被访问的邻接点出发深度优先遍历图,直至图中所有和 v 有路径相通的顶点都被访问
到;若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述
过程,直至图中所有顶点都被访问到为止。
以图 7-13(a)中无向图为例,对其进行深度优先搜索遍历的过程如图 7-13(c)所示,
其中黑色的实心箭头代表访问方向,空心箭头代表回溯方向,箭头旁的数字代表搜索顺序,
顶点 a 是起点。遍历过程如下:首先访问顶点 a,然后
a) 顶点 a 的未曾访问的邻接点有 b、 d、 e,选择邻接点 b 进行访问;
b) 顶点 b 的未曾访问的邻接点有 c、 e,选择邻接点 c 进行访问;
c) 顶点 c 的未曾访问的邻接点有 e、 f,选择邻接点 e 进行访问;
d) 顶点 e 的未曾访问的邻接点只有 f,访问 f;
e) 顶点 f 无未曾访问的邻接点,回溯至 e;
f) 顶点 e 无未曾访问的邻接点,回溯至 c;
g) 顶点 c 无未曾访问的邻接点,回溯至 b;
h) 顶点 b 无未曾访问的邻接点,回溯至 a;
i) 顶点 a 还有未曾访问的邻接点 d,访问 d;
j) 顶点 d 无未曾访问的邻接点,回溯至 a。
到此, a 再没有未曾访问的邻接点,也不能向前回溯,从 a 出发能够访问的顶点均已访问,并且此时图中再没有未曾访问的顶点,因此遍历结束。由以上过程得到的遍历序列为: a , b ,
c , e , f , d。
对于有向图而言,深度优先搜索的执行过程一样,例如图 7-13(b)中有向图的深度优
先搜索过程如图 7-13(d)所示。在这里需要注意的是从顶点 a 出发深度优先搜索只能访问
到 a , b , c , e , f,而无法访问到图中所有顶点,所以搜索需要从图中另一个未曾访问的顶点
d 开始进行新的搜索,即图 7-13(d)中的第 9 步

  public Iterator DFSTraverse(Vertex v) {
        LinkedList traverseSeq = new LinkedListDLNode();//遍历结果
        resetVexStatus(); //重置顶点状态
        DFSRecursion(v, traverseSeq); //从 v 点出发深度优先搜索
        Iterator it = getVertex(); //从图未曾访问的其他顶点重新搜索(调用图操作③)
        for (it.first(); !it.isDone(); it.next()) {
            Vertex u = (Vertex) it.currentItem();
            if (!u.isVisited()) DFSRecursion(u, traverseSeq);
        }
        return traverseSeq.elements();
    }

    //从顶点 v 出发深度优先搜索的递归算法
    private void DFSRecursion(Vertex v, LinkedList list) {
        v.setToVisited(); //设置顶点 v 为已访问
        list.insertLast(v); //访问顶点 v
        Iterator it = adjVertexs(v); //取得顶点 v 的所有邻接点(调用图操作⑧)
        for (it.first(); !it.isDone(); it.next()) {
            Vertex u = (Vertex) it.currentItem();
            if (!u.isVisited()) DFSRecursion(u, list);
        }
    }

 


    //从顶点 v 出发深度优先搜索的非递归算法
    private void DFS(Vertex v, LinkedList list) {
        Stack s = new StackSLinked();
        s.push(v);
        while (!s.isEmpty()) {
            Vertex u = (Vertex) s.pop(); //取栈顶元素
            if (!u.isVisited()) { //如果没有访问过
                u.setToVisited(); //访问之
                list.insertLast(u);
                Iterator it = adjVertexs(u); //未访问的邻接点入栈(调用图操作⑧)
                for (it.first(); !it.isDone(); it.next()) {
                    Vertex adj = (Vertex) it.currentItem();
                    if (!adj.isVisited()) s.push(adj);
                }//for
            }//if
        }//while
    }

    public Iterator BFSTraverse(Vertex v) {
        LinkedList traverseSeq = new LinkedListDLNode();//遍历结果
        resetVexStatus(); //重置顶点状态
        BFS(v, traverseSeq); //从 v 点出发广度优先搜索
        Iterator it = getVertex(); //从图中未访问的顶点重新搜索(调用图操作③)
        for (it.first(); !it.isDone(); it.next()) {
            Vertex u = (Vertex) it.currentItem();
            if (!u.isVisited()) BFS(u, traverseSeq);
        }
        return traverseSeq.elements();
    }

    private void BFS(Vertex v, LinkedList list) {
        Queue q = new QueueSLinked();
        v.setToVisited(); //访问顶点 v
        list.insertLast(v);
        q.enqueue(v); //顶点 v 入队
        while (!q.isEmpty()) {
            Vertex u = (Vertex) q.dequeue(); //队首元素出队
            Iterator it = adjVertexs(u); //访问其未曾访问的邻接点,并入队
            for (it.first(); !it.isDone(); it.next()) {
                Vertex adj = (Vertex) it.currentItem();
                if (!adj.isVisited()) {
                    adj.setToVisited();
                    list.insertLast(adj);
                    q.enqueue(adj);
                }//if
            }//for
        }//while
    }

首先,以顶点的成员变量 visited 来表示该
顶点是否属于 S, visited = true 表示属于 S,否则不属于 S。其次,到达 V-S 中各个顶点的最
短横切边通过该顶点的成员变量 application 来表示,此时 application 指向的是 Edge 类的对
象,它是从 S 到达本顶点横切边中权值最小的一条。在构造最小生成树过程中,对顶点成
员变量 application 的操作方法见代码 7-5。最后,最小生成树的表示采用设置图中边的类型
来完成,即如果是最小生成树的边,将边的类型设置为 Edge.MST。
 


    //获取到达顶点 v 的最小横切边权值
    protected int getCrossWeight(Vertex v) {
        if (getCrossEdge(v) != null)
            return getCrossEdge(v).getWeight();
        else return Integer.MAX_VALUE;
    }

    //获取到达顶点 v 的最小横切边
    protected Edge getCrossEdge(Vertex v) {
        return (Edge) v.getAppObj();
    }

    //设置到达顶点 v 的最小横切边
    protected void setCrossEdge(Vertex v, Edge e) {
        v.setAppObj(e);
    }
    public void generateMST() {
        resetVexStatus(); //重置图中各顶点的状态信息
        resetEdgeType(); //重置图中各边的类型信息
        Iterator it = getVertex(); //(调用图操作③)
        Vertex v = (Vertex) it.currentItem();//选第一个顶点作为起点
        v.setToVisited(); //顶点 v 进入集合 S

//初始化顶点集合 S 到 V-S 各顶点的最短横切边
        for (it.first(); !it.isDone(); it.next()) {
            Vertex u = (Vertex) it.currentItem();
            Edge e = edgeFromTo(v, u); //(调用图操作⑦)
            setCrossEdge(u, e); //设置到达 V-S 中顶点 u 的最短横切边
        }

        for (int t = 1; t < getVexNum(); t++) { //进行|V|-1 次循环找到|V|-1 条边
            Vertex k = selectMinVertex(it); //选择轻边在 V-S 中的顶点 k
            k.setToVisited(); //顶点 k 加入 S
            Edge mst = getCrossEdge(k); //割(S , V - S) 的轻边
            if (mst != null) mst.setToMST(); //将边加入 MST
//以 k 为中间顶点修改 S 到 V-S 中顶点的最短横切边
            Iterator adjIt = adjVertexs(k); //取出 k 的所有邻接点

            for (adjIt.first(); !adjIt.isDone(); adjIt.next()) {
                Vertex adjV = (Vertex) adjIt.currentItem();
                Edge e = edgeFromTo(k, adjV); //(调用图操作⑦)
                if (e.getWeight() < getCrossWeight(adjV))//发现到达 adjV 更短的横切边
                    setCrossEdge(adjV, e);
            }//for

        }//for(int t=1...
    }

    //查找轻边在 V-S 中的顶点
    protected Vertex selectMinVertex(Iterator it) {
        Vertex min = null;

        for (it.first(); !it.isDone(); it.next()) {
            Vertex v = (Vertex) it.currentItem();
            if (!v.isVisited()) {
                min = v;
                break;
            }
        }

        for (; !it.isDone(); it.next()) {
            Vertex v = (Vertex) it.currentItem();
            if (!v.isVisited() && getCrossWeight(v) < getCrossWeight(min))
                min = v;
        }
        return min;
    }

 

 

首先,以顶点 v 的成员变量 visited 来表示
该顶点是否属于 S, visited = true 表示属于 S,否则属于 V-S。其次,从 s 到达 V-S 中各个顶
点 v 的最短路径通过 v 的成员变量 application 来表示,此时 application 指向的是 Path 类的
对象。该对象是从 s 到达 v 的当前最短路径,其中包含 v 的当前最短距离 distance,以及取
得最短距离的路径上途经的顶点。在 Dijkstra 算法执行过程中,对顶点成员变量 application
的操作方法见代码 7-6。最后,求得从 s 到其余顶点的所有最短路径通过迭代器对象返回
 


    //取或设置顶点 v 的当前最短距离
    protected int getDistance(Vertex v) {
        return ((Path) v.getAppObj()).getDistance();
    }

    protected void setDistance(Vertex v, int dis) {
        ((Path) v.getAppObj()).setDistance(dis);
    }

    //取或设置顶点 v 的当前最短路径
    protected Path getPath(Vertex v) {
        return (Path) v.getAppObj();
    }

    protected void setPath(Vertex v, Path p) {
        v.setAppObj(p);
    }
  public class Path {
        private int distance; //起点与终点的距离
        private Vertex start; //起点信息
        private Vertex end; //终点信息
        private LinkedList pathInfo; //起点到终点途经的顶点序列

        //构造方法
        public Path() {
            this(Integer.MAX_VALUE, null, null);
        }

        public Path(int distance, Vertex start, Vertex end) {
            this.distance = distance;
            this.start = start;
            this.end = end;
            pathInfo = new LinkedListDLNode();
        }

        //判断起点与终点之间是否存在路径
        public boolean hasPath() {
            return distance != Integer.MAX_VALUE && start != null && end != null;
        }

        //求路径长度
        public int pathLength() {
            if (!hasPath()) return -1;
            else if (start == end) return 0;
            else return pathInfo.getSize() + 1;
        }

        //get&set methods
        public void setDistance(int dis) {
            distance = dis;
        }

        public void setStart(Vertex v) {
            start = v;
        }

        public void setEnd(Vertex v) {
            end = v;
        }

        public int getDistance() {
            return distance;
        }

        public Vertex getStart() {
            return start;
        }

        public Vertex getEnd() {
            return end;
        }

        public Iterator getPathInfo() {
            return pathInfo.elements();
        }

        //清空路经信息
        public void clearPathInfo() {
            pathInfo = new LinkedListDLNode();
        }

        //添加路径信息
        public void addPathInfo(Object info) {
            pathInfo.insertLast(info);
        }
    }
    public Iterator shortestPath(Vertex v) {
        LinkedList sPath = new LinkedListDLNode(); //所有的最短路径序列
        resetVexStatus(); //重置图中各顶点的状态信息
//初始化,将 v 到各顶点的最短距离初始化为由 v 直接可达的距离
        Iterator it = getVertex(); //(调用图操作③)

        for (it.first(); !it.isDone(); it.next()) {
            Vertex u = (Vertex) it.currentItem();
            int weight = Integer.MAX_VALUE;
            Edge e = edgeFromTo(v, u); //(调用图操作⑦)
            if (e != null) weight = e.getWeight();
            if (u == v) weight = 0;
            Path p = new Path(weight, v, u);
            setPath(u, p);
        }

        v.setToVisited(); //顶点 v 进入集合 S

        sPath.insertLast(getPath(v)); //求得的最短路径进入链接表

        for (int t = 1; t < getVexNum(); t++) { //进行|V|-1 次循环找到|V|-1 条最短路径
            Vertex k = selectMin(it); //找 V-S 中 distance 最小的点 k
            k.setToVisited(); //顶点 k 加入 S
            sPath.insertLast(getPath(k)); //求得的最短路径进入链接表
            int distK = getDistance(k); //修正 V-S 中顶点当前最短路径
            Iterator adjIt = adjVertexs(k); //取出 k 的所有邻接点

            for (adjIt.first(); !adjIt.isDone(); adjIt.next()) {
                Vertex adjV = (Vertex) adjIt.currentItem(); //k 的邻接点 adjV
                Edge e = edgeFromTo(k, adjV); //(调用图操作⑦)

//发现更短的路径
                if ((long) distK + (long) e.getWeight() < (long) getDistance(adjV)) {
                    setDistance(adjV, distK + e.getWeight());
                    amendPathInfo(k, adjV); //以 k 的路径信息修改 adjV 的路径信息
                }

            }//for

        }//for(int t=1...
        return sPath.elements();
    }

    //在顶点集合中选择路径距离最小的
    protected Vertex selectMin(Iterator it) {
        Vertex min = null;

        for (it.first(); !it.isDone(); it.next()) {
            Vertex v = (Vertex) it.currentItem();
            if (!v.isVisited()) {
                min = v;
                break;
            }
        }

        for (; !it.isDone(); it.next()) {
            Vertex v = (Vertex) it.currentItem();
            if (!v.isVisited() && getDistance(v) < getDistance(min))
                min = v;
        }

        return min;
    }

 为得到 AOV 网络的拓扑序列,可以使用以下方法:
⑴ 在 AOV 网络中选一个没有直接前驱的顶点,并输出之;
⑵ 从图中删去该顶点,同时删去所有它发出的有向边;
⑶ 重复以上⑴、⑵步, 直到全部顶点均已输出,或图中不存在无前驱的顶点。

//取或设置顶点 v 的当前入度

  private int getTopInDe(Vertex v) {
        return ((Integer) v.getAppObj()).intValue();
    }

    private void setTopInDe(Vertex v, int indegree) {
        v.setAppObj(Integer.valueOf(indegree));
    }

⑴ 建立入度为零的顶点栈;
⑵ 当入度为零的顶点栈不空时,重复执行
从顶点栈中退出一个顶点,并输出之;
搜索以这个顶点发出的边,将边的终顶点入度减 1;
如果边的终顶点入度减至 0,则该顶点进入栈;
⑶ 如果输出顶点个数少于 AOV 网络的顶点个数,说明网络中存在有向环。
在具体的算法实现中,我们使用每个顶点的 application 成员变量指向一个 Integer 对象,
它表示顶点在算法执行中当前的入度。在拓扑排序过程中对顶点成员变量 application 的操作
 

//取或设置顶点 v 的当前入度
    private int getTopInDe(Vertex v) {
        return ((Integer) v.getAppObj()).intValue();
    }

    private void setTopInDe(Vertex v, int indegree) {
        v.setAppObj(Integer.valueOf(indegree));
    }
 public Iterator toplogicalSort() {
        LinkedList topSeq = new LinkedListDLNode(); //拓扑序列
        Stack s = new StackSLinked();
        Iterator it = getVertex();
        for (it.first(); !it.isDone(); it.next()) { //初始化顶点集应用信息
            Vertex v = (Vertex) it.currentItem();
            v.setAppObj(Integer.valueOf(v.getInDeg()));
            if (v.getInDeg() == 0) s.push(v);
        }
        while (!s.isEmpty()) {
            Vertex v = (Vertex) s.pop();
            topSeq.insertLast(v); //生成拓扑序列
            Iterator adjIt = adjVertexs(v); //对于 v 的每个邻接点入度减 1
            for (adjIt.first(); !adjIt.isDone(); adjIt.next()) {
                Vertex adjV = (Vertex) adjIt.currentItem();
                int in = getTopInDe(adjV) - 1;
                setTopInDe(adjV, in);
                if (in == 0) s.push(adjV); //入度为 0 的顶点入栈
            }//for adjIt
        }//while
        if (topSeq.getSize() < getVexNum()) return null;
        else return topSeq.elements();
    }

 

    //求关键路径算法中,对 v.application 的操作
//取顶点 v 的最早开始时间与最迟开始时间
    private int getVE(Vertex v) {
        return ((Vtime) v.getAppObj()).getVE();
    }

    private int getVL(Vertex v) {
        return ((Vtime) v.getAppObj()).getVL();
    }

    //设置顶点 v 的最早开始时间与最迟开始时间
    private void setVE(Vertex v, int ve) {
        ((Vtime) v.getAppObj()).setVE(ve);
    }

    private void setVL(Vertex v, int vl) {
        ((Vtime) v.getAppObj()).setVL(vl);
    }
  public class Vtime {
        private int ve; //最早发生时间
        private int vl; //最迟发生时间

        //构造方法
        public Vtime() {
            this(0, Integer.MAX_VALUE);
        }

        public Vtime(int ve, int vl) {
            this.ve = ve;
            this.vl = vl;
        }

        //get&set method
        public int getVE() {
            return ve;
        }

        public int getVL() {
            return vl;
        }

        public void setVE(int t) {
            ve = t;
        }

        public void setVL(int t) {
            vl = t;
        }
    }
 public void criticalPath() {
        Iterator it = toplogicalSort();
        resetEdgeType(); //重置图中各边的类型信息
        if (it == null) return;
        LinkedList reTopSeq = new LinkedListDLNode(); //逆拓扑序列
        for (it.first(); !it.isDone(); it.next()) { //初始化各点 ve 与 vl,并生成逆拓扑序列
            Vertex v = (Vertex) it.currentItem();
            Vtime time = new Vtime(0, Integer.MAX_VALUE); //ve=0,vl=∞
            v.setAppObj(time);
            reTopSeq.insertFirst(v);
        }
        for (it.first(); !it.isDone(); it.next()) { //正向拓扑序列求各点 ve
            Vertex v = (Vertex) it.currentItem();
            Iterator adjIt = adjVertexs(v);
            for (adjIt.first(); !adjIt.isDone(); adjIt.next()) {
                Vertex adjV = (Vertex) adjIt.currentItem();
                Edge e = edgeFromTo(v, adjV);
                if (getVE(v) + e.getWeight() > getVE(adjV)) //更新最早开始时间
                    setVE(adjV, getVE(v) + e.getWeight());
            }

        }
        Vertex dest = (Vertex) reTopSeq.first().getData();
        setVL(dest, getVE(dest)); //设置汇点 vl=ve
        Iterator reIt = reTopSeq.elements();
        for (reIt.first(); !reIt.isDone(); reIt.next()) { //逆向拓扑序列求各点 vl
            Vertex v = (Vertex) reIt.currentItem();
            Iterator adjIt = adjVertexs(v);
            for (adjIt.first(); !adjIt.isDone(); adjIt.next()) {
                Vertex adjV = (Vertex) adjIt.currentItem();
                Edge e = edgeFromTo(v, adjV);
                if (getVL(v) > getVL(adjV) - e.getWeight()) //更新最迟开始时间
                    setVL(v, getVL(adjV) - e.getWeight());
            }
        }
        Iterator edIt = edges.elements();
        for (edIt.first(); !edIt.isDone(); edIt.next()) { //求关键活动
            Edge e = (Edge) edIt.currentItem();
            Vertex u = e.getFirstVex();
            Vertex v = e.getSecondVex();
            if (getVE(u) == getVL(v) - e.getWeight()) e.setToCritical();
        }
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值