图——最短路径,Dijstra算法

前几天讲了加权无向图的最小生成树,而今天讲的最短路径就是加权有向图的最小生成树。

定义:在一幅加权有向图中,从顶点s到顶点v的最短路径就是顶点s到顶点v所有路径中权重最小的那条路径。
如图所示:
图——最短路径,Dijstra算法_第1张图片

性质
①路径具有方向性
②权重不一定等价于距离,权重最小指的是成本最低
③只考虑连通图
④最短路径不一定是唯一的,只需要找出一条即可。
成员变量
private DirectedEdge[] edgeTo :索引代表顶点,值表示从顶点s到当前顶点的最短路径上的最后一条边
private double[] distTo : 索引代表顶点,值从顶点s到当前顶点的最短路径的总权重
private IndexMinPriorityQueue pq : 存放树中顶点与非树中顶点之间的有效横切边

边(v->w)的松弛
放松边v->w意味着检查从起点s到w的最短路径是否先从s到v,然后再从v到w?
如果是,则v->w这条边需要加入到最短路径树中,更新edgeTo和distTo中的内容:edgeTo[w]表示v->w这条边的DirectedEdge(加权边)对象,distTo[w]=distTo[v]+v->w这条边的权重; 如果不是,则忽略v->w这条边。如图所示:
图——最短路径,Dijstra算法_第2张图片图——最短路径,Dijstra算法_第3张图片
顶点的松弛
只需要把顶点指出的所有边松弛即可。

构造方法

 public DijkstraSP(EdgeWeightedDigraph G,int s){
        //初始化成员变量
        this.edgeTo=new DirectedEdge[G.getV()];
        this.distTo=new double[G.getV()];
        for (int i = 0; i < distTo.length; i++) {
            distTo[i]=Double.POSITIVE_INFINITY;
        }
        this.pq=new IndexMinPriorityQueue<>(G.getV());
        //找到G中以s为起点的最短路径树

        //默认让顶点s进去到最短路径树
        distTo[s]=0.0;
        pq.insert(s,0.0);
        //遍历pq
        while (!pq.isEmpty()){
            relax(G,pq.delMin());
        }
    }

松弛图G中的顶点v

private void relax(EdgeWeightedDigraph G,int v){
        for (DirectedEdge e : G.adj(v)) {
            //获取该变的终点w
            int w = e.to();
            //通过松弛技术,判断从起点s到w是否需要经过v到w这条边
            if (distTo(v)+e.weight()<distTo(w)){
                distTo[w]=distTo[v]+e.weight();
                edgeTo[w]=e;
                //判断pq是否已经存在w,如过存在,则更新权重,如果不在,则添加
                if (pq.contains(w)){
                    pq.changeItem(w,distTo(w));
                }else{
                    pq.insert(w,distTo(w));
                }
            }
        }
    }

查询从起点s到顶点v的最短路径中所有的边

public Queue<DirectedEdge> pathTo(int v){
        //判断顶点s到v是否可达,如果不可达,返回null;
        if (!haspathTo(v)){
            return null;
        }
        //创建一个队列
        Queue<DirectedEdge> alledges = new Queue<DirectedEdge>();
        while (true){
            DirectedEdge e = edgeTo[v];
            if (e==null){
                break;
            }
            alledges.enqueue(e);
            v=e.from();
        }
        return alledges;
    }

完整代码

public class DijkstraSP {
    //索引代表顶点,值表示从顶点s到当前顶点的最短路径上的最后一条边
    private DirectedEdge[] edgeTo;
    //索引代表顶点,值从顶点s到当前顶点的最短路径的总权重
    private double[] distTo;
    //存放树中顶点与非树中顶点之间的有效横切边
    private IndexMinPriorityQueue<Double> pq;
    //根据一副加权有向图G和顶点s,创建一个计算顶点为s的最短路径树对象
    public DijkstraSP(EdgeWeightedDigraph G,int s){
        //初始化成员变量
        this.edgeTo=new DirectedEdge[G.getV()];
        this.distTo=new double[G.getV()];
        for (int i = 0; i < distTo.length; i++) {
            distTo[i]=Double.POSITIVE_INFINITY;
        }
        this.pq=new IndexMinPriorityQueue<>(G.getV());
        //找到G中以s为起点的最短路径树
        //默认让顶点s进去到最短路径树
        distTo[s]=0.0;
        pq.insert(s,0.0);
        //遍历pq
        while (!pq.isEmpty()){
            relax(G,pq.delMin());
        }
    }
    //松弛图G中的顶点v
    private void relax(EdgeWeightedDigraph G,int v){
        for (DirectedEdge e : G.adj(v)) {
            //获取该变的终点w
            int w = e.to();
            //通过松弛技术,判断从起点s到w是否需要经过v到w这条边
            if (distTo(v)+e.weight()<distTo(w)){
                distTo[w]=distTo[v]+e.weight();
                edgeTo[w]=e;
                //判断pq是否已经存在w,如过存在,则更新权重,如果不在,则添加
                if (pq.contains(w)){
                    pq.changeItem(w,distTo(w));
                }else{
                    pq.insert(w,distTo(w));
                }
            }
        }
    }
    //获取从顶点s到顶点v的最短路径的总权重
    public double distTo(int v){
        return distTo[v];
    }
    //判断从顶点s到顶点v是否可达
    public boolean haspathTo(int v){
        return distTo[v]<Double.POSITIVE_INFINITY;
    }
    //查询从起点s到顶点v的最短路径中所有的边
    public Queue<DirectedEdge> pathTo(int v){
        //判断顶点s到v是否可达,如果不可达,返回null;
        if (!haspathTo(v)){
            return null;
        }
        //创建一个队列
        Queue<DirectedEdge> alledges = new Queue<DirectedEdge>();
        while (true){
            DirectedEdge e = edgeTo[v];
            if (e==null){
                break;
            }
            alledges.enqueue(e);
            v=e.from();
        }
        return alledges;
    }
}

b站详细讲解网址:http://yun.itheima.com/course/639.html

你可能感兴趣的:(Java数据结构,java,数据结构,有向图,算法)