最短路径算法
基于广度优先的Dijkstra算法,本算法针对的问题如下:
- 无向图
- 不带权
- 文件读取
- 最短路径算法
- JAVA实现
- 离线写博客
一 问题描述
1.无向图中某个顶点作为源点
2.求出图中所有顶点到源点的最短路径
二 算法实现思路
1.源点的最短路径距离为0,从源点开始,采用广度优先的顺序,首先将与源点邻接的顶点的路径求出,然后再依次求解图中其他顶点的最短路径。
2.由于顶点的最短路径的求解顺序 是一个 广度优先的顺序,因此需要一个辅助队列。初始时,将源点的最短路径距离设置为0,将源点入队列。
3.然后,在一个while循环中,从队列中弹出顶点,遍历该顶点的邻接点,若该邻接点的距离未被更新过(表示该邻接点未被访问过),更新邻接点的最短路径距离为 该顶点的距离加上1,并将所有的邻接点入队列。
三 测试结果:
保存文件:
0,0,1,4
1,0,2,7
2,0,3,3
3,1,2,3
4,1,4,2
5,3,4,3
6,2,5,2
7,4,5,2
四:代码
import java.io.File;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
public class NonDirectedGraph {
public static void main(String[] args) {
String graphFilePath;
if(args.length == 0)
graphFilePath = "F:\\xxx";
else
graphFilePath = args[0];
String graphContent = FileUtil.read(graphFilePath, null);//文件读取
NonDirectedGraph graph = new NonDirectedGraph(graphContent);//构建
graph.unweightedShortestPath();//算法实现
graph.showDistance();//展示
}
//起始点——声明
private Vertex startVertix;
//图——数据结构——哈希映射(键值对)
private Map<String, Vertex> nonDirectedGraph;
//无向图——构造器
public NonDirectedGraph(String graphContent) {
nonDirectedGraph=new LinkedHashMap<>();//哈希映射
buildGraph(graphContent);//构图
}
//构图——函数
private void buildGraph(String graphContent) {
String[] lines=graphContent.split("\n");//内容行数组
String startNodeLabel, endNodeLabel;//开始点的标签,结束点的标签
Vertex startNode, endNode;//开始结束点
for(int i=0;i<lines.length;i++){
String[] nodesInfo=lines[i].split(",");//每个顶点的信息
startNodeLabel=nodesInfo[1];//读取顶点信息,并且设置开始点的标签
endNodeLabel=nodesInfo[2];//同上
//根据标签获取结束点
endNode=nonDirectedGraph.get(endNodeLabel);//根据结束标签获得结束点
if(endNode==null){//结束点不存在
endNode=new Vertex(endNodeLabel);//新
nonDirectedGraph.put(endNodeLabel,endNode);//放入无向图
}
//根据标签获取开始点
startNode = nonDirectedGraph.get(startNodeLabel);
if(startNode == null){
startNode = new Vertex(startNodeLabel);
nonDirectedGraph.put(startNodeLabel, startNode);
}
//开始和结束点的边,对于无向图而言,起点和终点都要添加边
Edge e=new Edge(endNode);
endNode.adjEdge.add(e);
startNode.adjEdge.add(e);
}
//以文件中第一行第二列的那个标识顶点作为源点
startVertix=nonDirectedGraph.get(lines[0].split(",")[1]);
}
//顶点-定义
private class Vertex{
private String vertixLable="";//顶点是否已经访问的标志
private List<Edge> adjEdge;//顶点的邻接边
private int dist;//顶点距离上一顶点的距离
private Vertex preVertex;//上一个顶点
//构造函数
public Vertex(String vertixLable) {
this.vertixLable=vertixLable;//是否访问过
adjEdge=new LinkedList<>();//邻边列表
dist=Integer.MAX_VALUE;//距离初始化为最大值
preVertex=null;//上一顶点初始为空
}
}
//边-定义
private class Edge{
private Vertex endVeritx;//边的结束顶点
public Edge(Vertex endVeritx) {
this.endVeritx=endVeritx;
}
}
//实现算法
//无权最短路径,源点到无向图中各个顶点之间的最短路径
//需要一个队列来保存图中的顶点,初始时,源点入队列,然后以广度的形式向外扩散求解其他顶点的最短路径
private void unweightedShortestPath(Vertex s) {
Queue<Vertex> queue=new LinkedList<>();//顶点队列
s.dist=0;//源点距离初始为0
queue.offer(s);//源点入队列
while(!queue.isEmpty()) {//队列非空
Vertex v=queue.poll();//读取队列第一个元素
for(Edge e:v.adjEdge){//v 顶点的每个顶点
if(e.endVeritx.dist==Integer.MAX_VALUE){//如果这个顶点(e.endVertex)未被访问(每个顶点只会入队列一次)
e.endVeritx.dist=v.dist+1;//更新距离,加一个顶点
queue.offer(e.endVeritx);//结束顶点入队
e.endVeritx.preVertex=v;//结束顶点的前一个顶点为V顶点
}
}
}
}
public void unweightedShortestPath(){
unweightedShortestPath(startVertix);
}
//打印图中所有顶点到源点的距离及路径
public void showDistance() {
Collection<Vertex> vertexs=nonDirectedGraph.values();
for(Vertex vertex:vertexs){
System.out.print(vertex.vertixLable+"<——");
Vertex tempPreNode=vertex.preVertex;
while(tempPreNode!=null){
System.out.print(tempPreNode.vertixLable+"<——");
tempPreNode=tempPreNode.preVertex;
}
System.out.println("距离="+vertex.dist);
}
}
}