首先,在节点类改变了权值的成员变量pathLength起始为INFINITY(INFINITY设为10000),这样有助于寻找未访问节点中权值最小的点。边节点要增加一个表示权值的成员变量weight。
其次,在图类Graph中增添了两个方法,第一个是返回两节点之间的边getEdge(String start,String end),第二个是返回未访问节点中的权值最小的节点。并且修改Graph的建图方法,每条边加入权值的输入。
最后是主算法dijkstra();,并增添了一个输出方法以供输出完整的具体路径和路径长度。
Graph中增添的两个方法
//返回两个节点之间的边
public Edge getEdge(Vertex start, Vertex end)
{
Edge edge = start.first;
if(edge.nextEdge == null)
return edge;
else//说明不是第一条,需要通过链表找出另一条边
{
for(Edge e = edge; e != null ; e = e.nextEdge)
{
if(e.getTo().equals(end.getFrom()))
{
//找到符合条件的Edge赋给edge并退出循环
edge = e;
break;
}
}
}
return edge;
}
//返回未访问的节点中权值最小的节点
public Vertex getSmallestUnvisitedVertex()
{
Vertex smallestVertex = null;
//先找到第一个未被访问过的节点
for(int i = 0 ; i < v.length ; i ++)
{
if(!v[i].getIsVisted())
{
smallestVertex = v[i];
break;
}
}
for(int i= 0 ;i<v.length;i++)
{
if(!v[i].getIsVisted())
{
if(v[i].getPathlength() < smallestVertex.getPathlength())
smallestVertex = v[i];
}
}
return smallestVertex;
}
主算法以及测试:
package com.Algorithm.ShortestPath;
/*
*单元 dijkstra算法求最短路径
*/
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Scanner;
public class ValuedShortestPath {
Graph g;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ValuedShortestPath vsp = new ValuedShortestPath();
System.out.println("输入路径的起点和终点:");
Scanner input = new Scanner(System.in);
String first = input.next();
String end = input.next();
vsp.dijkstra(first);
vsp.printPath(first, end);
input.close();
}
//构造函数
public ValuedShortestPath()
{
g = new Graph();
g.buildGraph();
}
public void dijkstra(String first)
{
//通过初始节点名称找到初始节点并将其路径长度设为初始长度0
Vertex ver = g.v[g.findvIndex(first)];
ver.setPathlength(0);
System.out.println("从"+first+"出发的到各个节点的最短路径为:");
for(;;)
{
//对于所有的未被访问过的节点进行操作
//首先找到权值最小的节点,第一次就是第一个节点ver,以后每次都会更新
ver = g.getSmallestUnvisitedVertex();
if(ver == null) //如果找不到,说明所有节点都被访问过,结束循环
break;
ver.setIsVisted(true);
//输出到控制台
System.out.println( ver.getFrom()+"的路径长度为 "+ver.getPathlength()+",上一个节点是"+ver.getPath()+" ");
ArrayList<Vertex> al = g.getDirectedAdjacentVertex(ver);
for(Vertex vertex : al)
{
if(!vertex.getIsVisted())//对于没被访问过的节点
{
//找到相邻节点对应的边上的权值
Edge edge = g.getEdge(ver, vertex);
int weight = edge.getWeight();
//如果原节点+边权值仍小于这个相邻节点的值,则更新节点的值
if(vertex.getPathlength() > weight + ver.getPathlength() )
{
vertex.setPathlength(weight+ver.getPathlength());
//将这个相邻节点的path设为ver
vertex.setPath(ver.getFrom());
}
}
}
}
}
//通过输入开始节点和结束节点,输出最短路径的具体路径和路径长度
public void printPath(String start,String end)
{
System.out.println("从"+start+"到"+end+"的最短路径:");
//首先找到尾节点并得到最后一个path路径
Vertex tmpVertex = g.v[g.findvIndex(end)];
String tmpPath = tmpVertex.getFrom();
System.out.println("路径长度为" + tmpVertex.getPathlength() );
System.out.println("具体路径为:");
while( true )
{
//每次输出路径并更新tmpVertex和tmpPath
System.out.print(tmpPath + " ");
if(tmpVertex.getPath() != null)
tmpVertex = g.v[g.findvIndex(tmpVertex.getPath())];
else
break;
tmpPath = tmpVertex.getFrom();
}
}
}
测试结果:
原图为:
输入顶点数和边数:7 12
输入顶点名称:
v1 v2 v3 v4 v5 v6 v7
输入起点、终点和边的权值:v1 v2 2
输入起点、终点和边的权值:v1 v4 1
输入起点、终点和边的权值:v2 v4 3
输入起点、终点和边的权值:v2 v5 10
输入起点、终点和边的权值:v3 v1 4
输入起点、终点和边的权值:v3 v6 5
输入起点、终点和边的权值:v4 v3 2
输入起点、终点和边的权值:v4 v5 2
输入起点、终点和边的权值:v4 v7 4
输入起点、终点和边的权值:v4 v6 8
输入起点、终点和边的权值:v5 v7 6
输入起点、终点和边的权值:v7 v6 1
输入路径的起点和终点:
v1 v6
从v1出发的到各个节点的最短路径为:
v1的路径长度为 0,上一个节点是null
v4的路径长度为 1,上一个节点是v1
v2的路径长度为 2,上一个节点是v1
v3的路径长度为 3,上一个节点是v4
v5的路径长度为 3,上一个节点是v4
v7的路径长度为 5,上一个节点是v4
v6的路径长度为 6,上一个节点是v7
从v1到v6的最短路径:
路径长度为6
具体路径为:
v6 v7 v4 v1
这里要说明的一点是,最后输出的路径是逆序的,也就是从v1到v6的最短路径应该为v1 v4 v7 v6,这是算法所致,这里不再修改。