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

图这种adt(abstract data type)及相关的算法,之前一直是我未曾涉足过的领域。

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

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

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

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

1.图的两种表示方式:

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

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

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

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

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

测试用的图示例::《Java邻接表表示加权有向图,附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);
	}
}

测试结果:

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

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/wwhrestarting/article/details/51995104
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞