package com.example.demo.code90;
import com.example.demo.code10.queue.Queue;
import com.example.demo.code80.DirectedEdge;
import com.example.demo.code80.EdgeWeightedDigraph;
import com.example.demo.study.tree.youxianqueue.IndexMinPriorityQueue;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* @author ming
* @create 2022/6/20
* @description:
*/
public class DijkstraSP {
//索引代表顶点,值代表从顶点s到当前顶点的最短路径上的最后一条边
private DirectedEdge[] edgeTo;
//索引代表顶点,值从顶点s到当前顶点的最短路径的总权重
private double[] disTo;
//存放树中顶点与非树中顶点之间的有效横切边
private IndexMinPriorityQueue<Double> pq;
//根据一副加权有向图G和顶点s,创建一个计算顶点为s的最短路径的树对象
public DijkstraSP(EdgeWeightedDigraph G, int s) {
this.edgeTo = new DirectedEdge[G.v()];
//初始化disTo
this.disTo = new double[G.v()];
for (int i = 0; i < disTo.length; i++) {
disTo[i] = Double.MAX_VALUE;
}
this.pq = new IndexMinPriorityQueue(G.v());
//找到图G中以顶点s为起点的最短路径树
//默认让顶点s进入到最短路径树中
disTo[s] = 0.0;
pq.insert(s,0.0);
//遍历pq
while(!pq.isEmpty()){
relax(G,pq.delMin());
}
}
private void relax(EdgeWeightedDigraph g, int v) {
for (DirectedEdge edge : g.adj(v)) {
//获取该边的终点w
int w = edge.to();
//判断从起点s到顶点w是否需要先从顶点s到顶点v,然后再有顶点v到顶点w
if(disTo[v]+edge.weight()<disTo(w)){
disTo[w] = disTo[v]+edge.weight();
edgeTo[w] = edge;
//判断pq是否已经存在w,如果存在更新权重,如果不存在直接添加
if(pq.contains(w)){
pq.changeItem(w,disTo(w));
}else{
pq.insert(w,disTo(w));
}
}
}
}
//获取从顶点s到顶点v的最短路径的总权重
private double disTo(int v) {
return disTo[v];
}
//判断从顶点s到顶点v是否可达
public boolean hasPathTo(int v){
return disTo[v]<Double.MAX_VALUE;
}
//查询从起点s到顶点v的最短路径所有的边
public Queue<DirectedEdge> pathTo(int v){
if(!hasPathTo(v)){
return null;
}
//创建队列对象
Queue<DirectedEdge> allEdges = new Queue<>();
while(true){
DirectedEdge e = edgeTo[v];
if(e==null){
break;
}
allEdges.enqueue(e);
v = e.from();
}
return allEdges;
}
public static void main(String[] args) throws Exception {
/**
* 8
* 15
* 4 5 0.35
* 5 4 0.35
* 4 7 0.37
* 5 7 0.28
* 7 5 0.28
* 5 1 0.32
* 0 4 0.38
* 0 2 0.26
* 7 3 0.39
* 1 3 0.29
* 2 7 0.34
* 6 2 0.40
* 3 6 0.52
* 6 0 0.58
* 6 4 0.93
*/
//创建一副加权有向图
BufferedReader reader = new BufferedReader(new InputStreamReader(DijkstraSP.class.getClassLoader().getResourceAsStream("min_route_test.txt")));
int total = Integer.parseInt(reader.readLine());
EdgeWeightedDigraph G = new EdgeWeightedDigraph(total);
int edgeNumber = Integer.parseInt(reader.readLine());
for (int i = 0; i < edgeNumber; i++) {
String[] line = reader.readLine().split(" ");
int v = Integer.parseInt(line[0]);
int w = Integer.parseInt(line[1]);
double weight = Double.parseDouble(line[2]);
DirectedEdge e = new DirectedEdge(v, w, weight);
G.addEdge(e);
}
//创建DijksSp对象,查找最短路径树
DijkstraSP dijstraSp = new DijkstraSP(G, 0);
//查找最短路径 查找0-6的最短路径
Queue<DirectedEdge> directedEdges = dijstraSp.pathTo(6);
//遍历打印
for (DirectedEdge e : directedEdges) {
System.out.println(e.from()+"->"+e.to()+"::"+e.weight());
}
}
}