Dijkstra以及路径输出
算法原理
Dijkstra算法是利用广度优先搜索思想(BFS)的一种单源最短路径算法,相对于简单粗暴时间复杂度为O(n^3)的Floyed算法,(详情见我另一篇博客 只有五行的Floyed算法及全路径输出),Dijkstra算法的时间复杂度则有好的多,为O(n^2)。
该算法以起点为中心,将相邻边加入到优先队列中,每次取队列中的最短边,利用伸缩操作(relaxation),更新各点到源点的最近距离(这里用到了贪心算法原理), 存入到一个集合disTo中,该集合中记录每一个点到源点的最近距离,在pathTo集合中,设置此节点的上一节点。如果这点没有被访问过,就加入到优先队列中,就这样重复操作层层向外遍历,最后就可以生成一个最短路径树,对于从该源点到某一点的最短路径问题,只要看该点是否被访问过,被访问过的点说明存在最短路径,回溯pathTo集合,如pathTo(A) = B, B是使A到源点距离最近的相邻点(由贪心算法可知),pathTo(B) = C , C是使B到源点距离最近的相邻点,反复操作,直到pathTo(X) = 源点。即可得到最短路径
算法的主要函数
节点类
package Util;
public class Node {
private int x,y;
private String name;
public Node(int x, int y){
this.x = x;
this.y = y;
}
public Node(int x,int y,String name){
this.x = x;
this.y = y;
this.name = name;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public String getName(){
return name;
}
@Override
public boolean equals(Object o){
if(o instanceof Node){
return ((Node) o).getX()==this.x&&((Node) o).getY()==this.getY();
}
return false;
}
}
还有边类与无向图类,代码git
Dijkstra
public void start(){
if (this.undirectedGraph==null){
return;
}
pq.add(source);
while(!pq.isEmpty()){
Node n = pq.poll();
marked.add(n);
Iterator<UndirectedEdge> iterator = undirectedGraph.adj(n).iterator();
while (iterator.hasNext()){
UndirectedEdge adjNode = iterator.next();
Node other = adjNode.other(n);
if(disTo.get(other)>disTo.get(n)+adjNode.getDistance()
&&disTo.get(n)!=Integer.MAX_VALUE) {
disTo.put(other, disTo.get(n) + adjNode.getDistance());
pathTo.put(other,n);
}
if(!marked.contains(other))
pq.add(other);
}
}
实际用例:
public static void main(String[] args) {
Node[] nodeArrs = {new Node(0,2,"0"),new Node(1,9,"1"),new Node(2,3,"2"),
new Node(3,4,"3"),new Node(4,5,"4"),new Node(5,6,"5")};
UndirectedGraph undirectedGraph = new UndirectedGraph(nodeArrs[0],6,8);
undirectedGraph.addEdge(new UndirectedEdge(nodeArrs[0],nodeArrs[1],15));
undirectedGraph.addEdge(new UndirectedEdge(nodeArrs[0],nodeArrs[3],5));
undirectedGraph.addEdge(new UndirectedEdge(nodeArrs[1],nodeArrs[5],6));
undirectedGraph.addEdge(new UndirectedEdge(nodeArrs[3],nodeArrs[5],20));
undirectedGraph.addEdge(new UndirectedEdge(nodeArrs[3],nodeArrs[4],30));
undirectedGraph.addEdge(new UndirectedEdge(nodeArrs[1],nodeArrs[2],15));
undirectedGraph.addEdge(new UndirectedEdge(nodeArrs[2],nodeArrs[4],10));
undirectedGraph.addEdge(new UndirectedEdge(nodeArrs[4],nodeArrs[5],9));
Dijkstra dijkstra = new Dijkstra();
dijkstra.setUp(undirectedGraph);
dijkstra.start();
for(int i = 1;i<nodeArrs.length;i++){
if (dijkstra.hasPathTo(nodeArrs[i])){
System.out.print("Node0到Node"+nodeArrs[i].getName()+"的最短路径位:");
for (Node node:dijkstra.shortestPath(nodeArrs[i])){
System.out.print(node.getName()+"->");
}
System.out.println(dijkstra.shortestDistance(nodeArrs[i]));
}
}
}
结果