Dijkstra 算法: 适用于没有负权边的图,它以贪心的方式逐步确定从起始顶点到其他顶点的最短路径。算法的核心思想是每次选择当前最短路径的顶点,更新其相邻顶点的最短路径。
这是一个实现Dijkstra算法的Java程序,用于求有向图的最短路径。
-
类说明:
DirectNet1<T>
:表示有向图类。LocateVex(T v)
:在图中查找顶点v的位置。Dijkstra(int v0)
:实现Dijkstra算法,计算源点v0到其余顶点的最短路径。DisplayPath(int v0)
:输出源点v0到其余顶点的最短路径和路径长度。CreateAdj()
:根据用户输入创建图的邻接矩阵。
-
成员变量:
V
:顶点数组。arcs
:邻接矩阵,表示各个顶点之间的边的权值。e
:图的边数。n
:图的顶点数。path[]
:保存最短路径上的前驱顶点。dist[]
:保存源点到各顶点的最短路径长度。
-
主要方法解释:
Dijkstra(int v0)
:该方法使用Dijkstra算法计算从源点v0到其余顶点的最短路径。它使用了一个boolean数组s
来标记顶点是否在集合S中,dist
数组记录源点到各顶点的最短路径长度,path
数组保存最短路径上的前驱顶点。DisplayPath(int v0)
:该方法输出源点v0到其余顶点的最短路径和路径长度。
-
CreateAdj() 方法:
- 用户通过控制台输入图的顶点数、边数、顶点信息以及边的权值。
- 使用邻接矩阵表示有向图,
arcs[i][j]
表示顶点i到顶点j的边的权值。
-
Main 方法:
- 创建
DirectNet1
对象。 - 调用
CreateAdj()
方法创建有向图。 - 调用
Dijkstra(0)
计算从第一个顶点到其余顶点的最短路径。 - 调用
DisplayPath(0)
输出最短路径和路径长度。
- 创建
代码如下:
public class DirectNet1 <T>{
protected final int MAXSIZE=10;
protected final int MAX=999;
protected T[] V;
protected int[][] arcs;
protected int e;
protected int n;
int path[];
int dist[];
public DirectNet1(){
V=(T[])new Object[MAXSIZE];
arcs=new int[MAXSIZE][MAXSIZE];
path=new int[MAXSIZE];
dist=new int[MAXSIZE];
}
public int LocateVex(T v){
int i;
for(i=0;i<n;i++){
if(V[i]==v){
return i;
}
}
return -1;
}
//求有向图G的v0顶点到其余顶点v的最短路径
public void Dijkstra(int v0){
int i,j,v=0,w=0;
int min;
boolean[] s=new boolean[MAXSIZE];
for(i=0;i<n;i++){//初始化s,dist和path
s[i]=false;
dist[i]=arcs[v0][i];
if(dist[i]<MAX)path[i]=v0;
else path[i]=-1;
}
dist[v0]=0;s[v0]=true;//初始时源点v0属于s集
//循环求v0到某个顶点v的最短路径,并将v加入s集
for(i=1;i<n-1;i++){
min= MAX;
for(w=0;w<n;w++){
//顶点w不属于s集,且离v0更近
if(!s[w]&&dist[w]<min){
v=w;min=dist[w];
}
}
s[v]=true;//顶点v并入s
for(j=0;j<n;j++){//更新当前最短路径及距离
if(!s[j]&&(min+arcs[v][j]<dist[j])){
dist[j]=min+arcs[v][j];
path[j]=v;
}
}
}
}
//输出源点v0到其余顶点的最短路径和路径长度
public void DisplayPath(int v0){
int i,next;
for(i=0;i<n;i++){
if(dist[i]< MAX &&i!=v0){
System.out.print("V"+i+"<--");
next=path[i];
while(next!=v0){
System.out.print("V"+next+"<--");
next=path[next];
}
System.out.println("V"+v0+":"+dist[i]);
}
else
if(i!=v0)
System.out.println("V"+i+"<--V"+v0+":no path");
}
}
public void CreateAdj() {
int i, j, k;
T v1, v2;
Scanner sc = new Scanner(System.in);
System.out.println("请输入图的顶点数和边数:");
System.out.println("顶点数 n = ");
n = sc.nextInt();
System.out.println("边数 e = ");
e = sc.nextInt();
System.out.println("请输入图的顶点信息:");
String str = sc.next();
for (i = 0; i < n; i++) {
V[i] = (T)(Object)str.charAt(i);
}
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
arcs[i][j] = MAX;
}
}
System.out.println("请输入图的边信息:");
for (k = 0; k < e; k++) {
System.out.println("请输入第" + (k + 1) + "条边的两个顶点和权值:");
v1 = (T)(Object)sc.next().charAt(0);
v2 = (T)(Object)sc.next().charAt(0);
int weight = sc.nextInt(); // 获取输入的权值
i = LocateVex(v1);
j = LocateVex(v2);
if (i >= 0 && j >= 0) {
arcs[i][j] = weight;
arcs[j][i] = weight; // 如果需要无向图,保留这句
} else {
System.out.println("输入的顶点信息不合法,请重新输入。");
k--; // 使得循环变量 k 不增加,重新输入当前边
}
}
}
public static void main(String[] args) {
DirectNet1<Character> G=new DirectNet1<Character>();
G.CreateAdj();
G.Dijkstra(0);
G.DisplayPath(0);
}
}