最短路径Dijkstra算法

最短路径

最短路径的性质:

  • 路径是有向的
  • 权重不一定等价于距离,权重也可以指时间,花费或者其他
  • 并不是所有顶点都是可达的
  • 负权重会使得问题更复杂(Dijkstra算法不适用于这种情况)
  • 最短路径一般都是简单的,这里算法会忽略构成环的零权重边,找到的最短路径都不会有环
  • 最短路径不一定是唯一的
  • 可能存在平行边和自环

最短路径树:给出起点s,计算结果是一颗最短路径树(Shortest Path Tree SPT),它包含了顶点s到所有可达顶点的最短路径

数据结构:

  • 最短路径树中的边edgeTo[],edgeTo[v]表示s到v的最短路径中的最后一条边
  • 到达起点的距离distTo[],distTo[v]表示s到v的已知最短路径长度

Dijkstra 算法

取自<算法>第四版-算法4.9

该算法类似Prim及时算法


    private double[] distTo;          // distTo[v] = distance  of shortest s->v path
    private DirectedEdge[] edgeTo;    // edgeTo[v] = last edge on shortest s->v path
    private IndexMinPQ<Double> pq;	  // priority queue of vertices

	public DijkstraSP(EdgeWeightedDigraph G, int s) { 
		// 起点到各个顶点v的距离
        distTo = new double[G.V()];
        // 起点到各个顶点v最短路径中的最后一条边
        edgeTo = new DirectedEdge[G.V()];

        // 初始化起点s到各个顶点的距离为无穷最大值
        for (int v = 0; v < G.V(); v++) {
            distTo[v] = Double.POSITIVE_INFINITY;
        }
        distTo[s] = 0.0;

        // 从s到顶点v的权重为优先级
        pq = new IndexMinPQ<Double>(G.V());
        // s为起点
        pq.insert(s, distTo[s]);
        while (!pq.isEmpty()) {
            // 取出顶点v
            int v = pq.delMin();
            // 遍历顶点v的各个边
            for (DirectedEdge e : G.adj(v)) {
                relax(e);
            }
        }
	}

    // 松弛一个顶点,判断起点s到顶点w的最短路径是否是s -> v -> w
    private void relax(DirectedEdge e) {
        // 边e为从顶点v到顶点w的有向边
        int v = e.from(), w = e.to();
        // 如果s到w的距离大于s到v + v到w的距离,则更新该距离,并将顶点w存入优先级队列
        if (distTo[w] > distTo[v] + e.weight()) {
            distTo[w] = distTo[v] + e.weight();
            edgeTo[w] = e;
            // 如果队列中已存在顶点w,则需要更新s到顶点w的距离,也即是更新权重
            if (pq.contains(w)) {
                pq.decreaseKey(w, distTo[w]);
            } else {
                pq.insert(w, distTo[w]);
            }               
        }
    }

    // 判断起点s到顶点v是否可达
    public boolean hasPathTo(int v) {
        return distTo[v] < Double.POSITIVE_INFINITY;
    }

	// 获取起点s到顶点v的最短路径
    public Iterable<DirectedEdge> pathTo(int v) {
        if (!hasPathTo(v)) {
            return null;
        }
        Stack<DirectedEdge> path = new Stack<DirectedEdge>();
        for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()]) {
            path.push(e);
        }
        return path;
    }

空间复杂度:V

时间复杂度:ElogV

给定两点s->t的最短路径:可使用Dijkstra算法并在优先队列中取到t之后终止搜索

任意顶点之间的最短路径:遍历各个顶点构造最短路径树,时间及空间复杂度均为EVlogV

加权无环图

加权无环图:加权有向图中不含有有向环的图

可在线性时间内解决加权无环图中的最短路径问题,比Dijkstra算法更快

  • 可在线性时间内解决单点最短路径问题
  • 能够处理负权重的边

待补充...

负权重的加权有向图

负权重的加权有向图:可能含有环也可能含有负权重的边的加权有向图

Bellman-Ford算法:时间复杂度EV,空间复杂度V

大佬自行研究去吧,我该curd去了

posted @   Abserver  阅读(119)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示