问题阐述:从文件中读入一个有向加权图,输入源点source,求源点到其他所有顶点的最短路径。
简单应用:比如说,你想从你居住的城市A去城市B、C、D旅游,从A到B、C、D都有很多交通路线,从这些交通路线中分别选出A到B、A到C、A到D的花钱最少的路线。
我的源程序(含测试用的代码):
//用Dijstra算法解有向加权图的单源最短路径问题,没有求出具体路径
//文件格式:如5 2 4 9999,表示这条边的起点为5,终点为2,5->2的权为4,但2没有指向5,所以2->5的权为99999(表示无穷大)
//用邻接链表来存储图,用堆栈实现优先队列
import java.io.*;
import java.util.*;
class Edge{
int adj;//邻接点
int w;//边的权
}
class Vertex{
int order;//该点输入时的顺序
int dis;//该点与源点的距离
Edge adjE[];//该点的邻边
}
class Dijkstra{
int source;//源点
int vNum;//顶点数
int eNum;//边数
int eNumV[];//记录每个顶点的出度边数
int flag[];//判断是否已经求出该点与源点的最短路径的标志
ArrayList e;//存放每一条边
Vertex v[];//顶点
Vertex top;//堆顶
ArrayList path[];//记录从源点出发到每个点的最短路径
public Dijkstra(String fileName,int source)throws IOException{
this.source=source;
vNum=0;
eNum=0;
e=new ArrayList();
FileReader fr=new FileReader(fileName);
BufferedReader bf=new BufferedReader(fr);
String s;
do{
s=bf.readLine();
if(s!=null) {e.add(s);System.out.println(s);}
}while(s!=null);
System.out.println(e);//
eNum=e.size();
int i,start=0,end=0;
//第一次字符串处理,保存每一条边,以及获得顶点总数vNum
for(i=0,vNum=0;i<eNum;i++){
StringBuffer sb=new StringBuffer(e.get(i).toString());
start=Integer.parseInt(sb.substring(0,sb.indexOf(" ")));
if(start>vNum) vNum=start;
sb.delete(0,sb.indexOf(" ")+1);
end=Integer.parseInt(sb.substring(0,sb.indexOf(" ")));
if(end>vNum) vNum=end;
}//for
System.out.println("vNum:"+vNum);//
System.out.println("eNum:"+eNum);//
flag=new int[vNum+1];
path=new ArrayList[vNum+1];
for(i=1;i<=vNum;i++){
path[i]=new ArrayList();
path[i].add(source);
if(i==source) flag[i]=1;
else flag[i]=0;
}
//第二次字符串处理,获得每个顶点的出度边数
eNumV=new int[vNum+1];
for(i=1;i<eNumV.length;i++) eNumV[i]=0;
int w1=0,w2=0;//w1表示入度,w2表示出度
for(i=0;i<eNum;i++){
StringBuffer sb=new StringBuffer(e.get(i).toString());
start=Integer.parseInt(sb.substring(0,sb.indexOf(" ")));
sb.delete(0,sb.indexOf(" ")+1);
end=Integer.parseInt(sb.substring(0,sb.indexOf(" ")));
sb.delete(0,sb.indexOf(" ")+1);
w1=Integer.parseInt(sb.substring(0,sb.indexOf(" ")));
if(w1!=99999) eNumV[start]++;
sb.delete(0,sb.indexOf(" ")+1);
w2=Integer.parseInt(sb.toString());
if(w2!=99999) eNumV[end]++;
}//for
for(i=1;i<eNumV.length;i++) System.out.print(eNumV[i]+" ");//
//第三次字符串处理,建立图的邻接链表
v=new Vertex[vNum+1];i=1;
for(i=1;i<vNum+1;i++){
v[i]=new Vertex();
v[i].adjE=new Edge[eNumV[i]+1];
v[i].order=i;
if(i==source) v[i].dis=100000;
else v[i].dis=99999;
for(int j=1;j<=eNumV[i];j++) v[i].adjE[j]=new Edge();
}//for
int temp[]=new int[vNum+1];//eNumV的缓存
for(i=1;i<vNum+1;i++) temp[i]=1;
for(i=0;i<eNum;i++){//System.out.println("i:"+i);//
StringBuffer sb=new StringBuffer(e.get(i).toString());
start=Integer.parseInt(sb.substring(0,sb.indexOf(" ")));
sb.delete(0,sb.indexOf(" ")+1);
end=Integer.parseInt(sb.substring(0,sb.indexOf(" ")));
v[start].adjE[temp[start]].adj=end;
v[end].adjE[temp[end]].adj=start;//?
sb.delete(0,sb.indexOf(" ")+1);
w1=Integer.parseInt(sb.substring(0,sb.indexOf(" ")));
v[start].adjE[temp[start]].w=w1;
sb.delete(0,sb.indexOf(" ")+1);
w2=Integer.parseInt(sb.toString());
v[end].adjE[temp[end]].w=w2;//?
//System.out.println("source:"+source);//
if(start<source&&end==source) v[start].dis=w2;
else if(start==source) v[end].dis=w1;
if(temp[start]<eNumV[start]) temp[start]++;
if(temp[end]<eNumV[end]) temp[end]++;
}//for
for(i=1;i<vNum+1;i++){
System.out.println("v"+i);
System.out.println("v["+i+"].order:"+v[i].order);
System.out.println("v["+i+"].dis:"+v[i].dis);
for(int j=1;j<=eNumV[i];j++){
System.out.println("v["+i+"].adj["+j+"].adj:"+v[i].adjE[j].adj);
System.out.println("v["+i+"].adj["+j+"].w:"+v[i].adjE[j].w);
}
System.out.println();
}//
}//Dijkstra
public Vertex creatHeap(Vertex v[],int end){//难在调整后怎么知道堆顶是哪一条边
Vertex temp=v[1];
for(int i=end/2;i>0;i--){//换节点(即边)
if(2*i+1<=end&&v[2*i+1].dis<v[2*i].dis&&v[i].dis>v[2*i+1].dis){
//System.out.println("/n"+v[i].dis+" "+v[2*i].dis+" "+v[2*i+1].dis);//
temp=v[i];v[i]=v[2*i+1];v[2*i+1]=temp;
//System.out.println("/n"+v[i].start+" "+v[i].end);//
}
else if(v[i].dis>v[2*i].dis){
//System.out.println("/n"+v[i].dis+" "+v[2*i].dis);//
temp=v[i];v[i]=v[2*i];v[2*i]=temp;
//System.out.println("/n"+v[i].start+" "+v[i].end);//
}
}//for
top=v[1];
//System.out.println("top.order:"+top.order);//
flag[v[1].order]=1;
return top;//返回堆顶
}//creatHeap
public void update(Vertex v[],int end){
Vertex temp;
//System.out.println("/nv[1].order:"+v[1].order);//
temp=v[1];v[1]=v[end];v[end]=temp;//把堆顶取出,用堆底替换
//System.out.println("v[1].order:"+v[1].order);//
//System.out.println("v[end].order:"+v[end].order);//
path[v[end].order].add(v[end].order);
for(int i=1;i<v[end].adjE.length;i++){
int vTemp1=v[end].adjE[i].adj,vTemp2=0;
//System.out.println("vTemp1:"+vTemp1);//
for(int j=1;j<=end;j++){
if(vTemp1==source) break;
else if(v[j].order==vTemp1) {vTemp2=vTemp1;vTemp1=j;break;}
}
//System.out.println("vTemp1:"+vTemp1);//
if(vTemp2!=0&&vTemp2!=source&&v[end].dis+v[end].adjE[i].w<v[vTemp1].dis){
//System.out.println("v[vTemp1].dis:"+v[vTemp1].dis);//
v[vTemp1].dis=v[end].dis+v[end].adjE[i].w;
//System.out.println("v[vTemp1].dis:"+v[vTemp1].dis);//
path[vTemp1].add(v[end].order);
}
}
}
}
public class DijkstraTest {
public DijkstraTest() {
}
public static void main(String args[])throws IOException{
Dijkstra test=new Dijkstra("DijTest2.TXT",3);
int temp=test.vNum;
while(temp>1){
test.creatHeap(test.v,temp);
test.update(test.v,temp);
temp--;
}
for(int i=1;i<=test.vNum;i++){
for(int j=1;j<=test.vNum;j++){
if(test.v[j].order==i){
System.out.println("v["+test.v[j].order+"].dis:"+test.v[j].dis);//
//System.out.println(test.path[test.v[j].order]);//
}
}
}
}
}