最短路径
最短路径应用的图是加权有向图
加权有向图的数据结构:
首先定义的是加权有向边的数据类型:
public class DirectEdge {
private int v;//边的起点
private int w;//边的终点
private double weight;//边的权重
public DirectEdge(int v,int w,double weight){
this.v=v;
this.w=w;
this.weight=weight;
}
public double weight(){
return weight;
}
public int from(){
return v;
}
public int to(){
return w;
}
public String toString(){
return String.format("%d->%d %.2f", v,w,weight);
}
} ```
在加权有向边的基础上定义加权有向图
```java
public class EdgeWeightDigraph {
private int V;
private int E;
private Bag<DirectEdge>[] adj;
public EdgeWeightDigraph(int V){
this.V=V;
this.E=0;
adj=(Bag<DirectEdge>[])new Bag[V];
for(int v=0;v<V;v++){
adj[v]=new Bag<DirectEdge>();
}
}
public int V(){
return V;
}
public int E(){
return E;
}
public void addEdge(DirectEdge e){
int v=e.from();
adj[v].add(e);
E++;
}
public Iterable<DirectEdge> adj(int v){
return adj[v];
}
public Iterable<DirectEdge> edges(){
Bag<DirectEdge> bag=new Bag<DirectEdge>();
for(int v=0;v<V;v++){
for(DirectEdge e:adj[v]){
bag.add(e);
}
}
return bag;
}
}
最短路径:从图的一个顶点到达另一个顶点的成本最小(权重和最小)的路径,这里的最短路径是单点最短路径
最短路径树: 给定一幅加权有向图和顶点s,可以找到一个以s为起点的最小路径树,他是图的一幅子图,包含了顶点s和所有s可达的顶点。树的根节点是s,树的每一条路径都是有向图中的一条最短路径
最短路径算法原理
边的松弛
顶点的松弛
最短路径的最优条件:
一幅有向加权图G,顶点s为起点,distTo[]保存着起点s到任意顶点v的路径长度,若s到v不可达,该值为无穷大。当且仅当对于从v到w的任意一条边e,满足**distTo[w]<=distTo[v]+e.weight()**条件时,才是最短路径
Dijkstra算法
- 算法思想
- 首先Dijkstra算法只适用在权值非负的加权有向图
如下图所示,E(v2,v5)为负值,如果想找到v5到v4的最短路径,那么这一条路径:v5->v4->v2->v5->v4的权值之和为-6,如此一直沿着这条路径循环,那么v5到v4的路径权重之和会越来越小,趋近于负无穷,那么这两个顶点之间的最短路径无法确定。我们称图中这样的循环为负值圈,有向图中出现负值圈时,最短路径的问题就无法确定。
2)Dijkstra算法的思想
首先确定源点s,dist[v]表示的是从s到v的最短路径距离
Dijkstra算法每次从没有确定最短路径的顶点中选择dist[]值最小的顶点v,对v的所有边进行松弛,如此操作直到确定所有顶点的最短路径
- 首先Dijkstra算法只适用在权值非负的加权有向图
- 算法实现
public class Dijkstra {
private DirectEdge[] edgeTo;
private double[] distTo;
private IndexMinPQ<Double> pq;
public Dijkstra(EdgeWeightDigraph G,int s){
edgeTo=new DirectEdge[G.V()];
distTo=new double[G.V()];
pq=new IndexMinPQ