您的位置:首页 > 编程语言 > Java开发

Java邻接表表示加权有向图,附dijkstra最短路径算法

2016-07-22 15:41 686 查看
图这种adt(abstract data type)及相关的算法,之前一直是我未曾涉足过的领域。

主要是作为一个小测试,在平常的工作中也用不着,就算面试,至今也未曾碰到过相关考题。

但是前几天,原公司的小美女谈到面试过程中就碰到一题:

从A到B,有多条路线,要找出最短路线,应该用哪种数据结构来存储这些数据。

等等,这不是显然的考查图论的相关知识了么,

1.图的两种表示方式:

邻接矩阵:二维数组搞定。

邻接表:Map<Vertext,List<Edge>>搞定

其中临街矩阵适用于稠密图,即图上的任意两点之间均(差不多都)存在一条边。

而A到B之间的路线,显然是稀疏图,果断的选用邻接表。

2.加权有向图最短路径问题,典型的dijkstra最短路径算法。

测试用的图示例::


说干就干,翻翻《数据结构与算法》,自己用Java大概实现了一下,可能有bug,欢迎交流,具体代码如下:

package base.algorithm;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class Graph{

private List<Vertex> vertexList; //图的顶点集
private Map<Vertex, List<Edge>> ver_edgeList_map; //图的每个顶点对应的有向边

public Graph(List<Vertex> vertexList, Map<Vertex, List<Edge>> ver_edgeList_map) {
super();
this.vertexList = vertexList;
this.ver_edgeList_map = ver_edgeList_map;
}

public List<Vertex> getVertexList() {
return vertexList;
}

public void setVertexList(List<Vertex> vertexList) {
this.vertexList = vertexList;
}

public Map<Vertex, List<Edge>> getVer_edgeList_map() {
return ver_edgeList_map;
}

public void setVer_edgeList_map(Map<Vertex, List<Edge>> ver_edgeList_map) {
this.ver_edgeList_map = ver_edgeList_map;
}

static class Edge{
private Vertex startVertex; //此有向边的起始点
private Vertex endVertex; //此有向边的终点
private int weight; //此有向边的权值

public Edge(Vertex startVertex, Vertex endVertex, int weight) {
super();
this.startVertex = startVertex;
this.endVertex = endVertex;
this.weight = weight;
}

public Edge()
{}

public Vertex getStartVertex() {
return startVertex;
}
public void setStartVertex(Vertex startVertex) {
this.startVertex = startVertex;
}
public Vertex getEndVertex() {
return endVertex;
}
public void setEndVertex(Vertex endVertex) {
this.endVertex = endVertex;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}

static class Vertex {
private final static int infinite_dis = Integer.MAX_VALUE;

private String name; //节点名字
private boolean known; //此节点之前是否已知
private int adjuDist; //此节点距离
private Vertex parent; //当前从初始节点到此节点的最短路径下,的父节点。

public Vertex()
{
this.known = false;
this.adjuDist = infinite_dis;
this.parent = null;
}

public Vertex(String name)
{
this.known = false;
this.adjuDist = infinite_dis;
this.parent = null;
this.name = name;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isKnown() {
return known;
}
public void setKnown(boolean known) {
this.known = known;
}
public int getAdjuDist() {
return adjuDist;
}
public void setAdjuDist(int adjuDist) {
this.adjuDist = adjuDist;
}

public Vertex getParent() {
return parent;
}

public void setParent(Vertex parent) {
this.parent = parent;
}

/**
* 重新Object父类的equals方法
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Vertex)) {
throw new ClassCastException("an object to compare with a Vertext must be Vertex");
}

if (this.name==null) {
throw new NullPointerException("name of Vertex to be compared cannot be null");
}

return this.name.equals(obj);
}
}

public void setRoot(Vertex v)
{
v.setParent(null);
v.setAdjuDist(0);
}

/**
*
* @param startIndex dijkstra遍历的起点节点下标
* @param destIndex dijkstra遍历的终点节点下标
*/
public void dijkstraTravasal(int startIndex,int destIndex)
{
Vertex start = vertexList.get(startIndex);
Vertex dest = vertexList.get(destIndex);
String path = "["+dest.getName()+"]";

setRoot(start);
updateChildren(vertexList.get(startIndex));

int shortest_length = dest.getAdjuDist();

while((dest.getParent()!=null)&&(!dest.equals(start)))
{
path = "["+dest.getParent().getName()+"] --> "+path;
dest = dest.getParent();
}

System.out.println("["+vertexList.get(startIndex).getName() +"] to ["+
vertexList.get(destIndex).getName()+"] dijkstra shortest path :: "+path);
System.out.println("shortest length::"+shortest_length);
}

/**
* 从初始节点开始递归更新邻接表
* @param v
*/
private void updateChildren(Vertex v)
{
if (v==null) {
return;
}

if (ver_edgeList_map.get(v)==null||ver_edgeList_map.get(v).size()==0) {
return;
}

List<Vertex> childrenList = new LinkedList<Graph.Vertex>();
for(Edge e:ver_edgeList_map.get(v))
{
Vertex childVertex = e.getEndVertex();

//如果子节点之前未知,则把当前子节点假如更新列表
if(!childVertex.isKnown())
{
childVertex.setKnown(true);
childVertex.setAdjuDist(v.getAdjuDist()+e.getWeight());
childVertex.setParent(v);
childrenList.add(childVertex);
}

//子节点之前已知,则比较子节点的ajduDist&&nowDist
int nowDist = v.getAdjuDist()+e.getWeight();
if(nowDist>=childVertex.getAdjuDist())
{
continue;
}
else {
childVertex.setAdjuDist(nowDist);
childVertex.setParent(v);
}
}

//更新每一个子节点
for(Vertex vc:childrenList)
{
updateChildren(vc);
}
}

}



测试代码:

package base.algorithm;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import base.algorithm.Graph.Edge;
import base.algorithm.Graph.Vertex;

/**
* 测试用main方法
* @author wuhui.wwh
*
*/
public class TestGraph {
public static void main(String[] args) {
Vertex v1= new Vertex("v1");
Vertex v2= new Vertex("v2");
Vertex v3= new Vertex("v3");
Vertex v4= new Vertex("v4");
Vertex v5= new Vertex("v5");
Vertex v6= new Vertex("v6");
Vertex v7= new Vertex("v7");
Vertex v8= new Vertex("v8");

List<Vertex> verList = new LinkedList<Graph.Vertex>();
verList.add(v1);
verList.add(v2);
verList.add(v3);
verList.add(v4);
verList.add(v5);
verList.add(v6);
verList.add(v7);
verList.add(v8);

Map<Vertex, List<Edge>> vertex_edgeList_map = new HashMap<Graph.Vertex, List<Edge>>();

List<Edge> v1List = new LinkedList<Graph.Edge>();
v1List.add(new Edge(v1,v2,6));
v1List.add(new Edge(v1,v4,1));
v1List.add(new Edge(v1,v4,1));

List<Edge> v2List = new LinkedList<Graph.Edge>();
v2List.add(new Edge(v2,v3,43));
v2List.add(new Edge(v2,v4,11));
v2List.add(new Edge(v2,v5,6));

List<Edge> v3List = new LinkedList<Graph.Edge>();
v3List.add(new Edge(v3,v8,8));

List<Edge> v4List = new LinkedList<Graph.Edge>();
v4List.add(new Edge(v4,v3,15));
v4List.add(new Edge(v4,v5,12));

List<Edge> v5List = new LinkedList<Graph.Edge>();
v5List.add(new Edge(v5,v3,38));
v5List.add(new Edge(v5,v8,13));
v5List.add(new Edge(v5,v7,24));

List<Edge> v6List = new LinkedList<Graph.Edge>();
v6List.add(new Edge(v6,v5,1));
v6List.add(new Edge(v6,v7,12));

List<Edge> v7List = new LinkedList<Graph.Edge>();
v7List.add(new Edge(v7,v8,20));

vertex_edgeList_map.put(v1, v1List);
vertex_edgeList_map.put(v2, v2List);
vertex_edgeList_map.put(v3, v3List);
vertex_edgeList_map.put(v4, v4List);
vertex_edgeList_map.put(v5, v5List);
vertex_edgeList_map.put(v6, v6List);
vertex_edgeList_map.put(v7, v7List);

Graph g = new Graph(verList, vertex_edgeList_map);
// g.dijkstraTravasal(1, 5);
g.dijkstraTravasal(0, 7);
}
}


测试结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: