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

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

1.图的两种表示方式:

邻接矩阵:二维数组搞定

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

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

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

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

说干就干,翻翻《数据结构与算法》,自己用Java大概实现了一下,具体代码如下:

实现思路:

1,定义一个类:有向图类:Graph。

有向图类的子类:节点类:Vertex,边类:Vertex。

节点类:保存节点名称,上一个节点,长度等属性。

边节点:保存每条边的两边的节点,通过边找到对应的另一条节点。

2,该类有两个属性:

1,List<Vertex> vertexList:保存图的顶点集合,便于遍历顶点的时候查找对应集合。
2,Map<Vertex, List<Edge>> ver_edgeList_map:图的每个顶点对应的有向边。

3,为了能够记录最短路径,需要为每个节点定义一个属性:父节点,表示父节点到该点的距离最短。

3,每个节点有多个属性:

String name;  //节点名字
boolean known; //此节点之前是否已知,如果未知的话,则需要初始化距离adjuDist和parent属性
int adjuDist; //保存从开始节点到此节点距离
Vertex parent; //当前从初始节点到此节点的最短路径下,的父节点。

4,从起点节点开始查找。

比较规则:从A节点开始比较,对其指向的B节点进行初始化和比较:

如果B节点未被初始化,先设置该B节点的父节点为A节点,距离为边长加上A节点的adjuDist。

如果已经初始化完了,则重新比较:

如果A节点加边长小于B节点的adjuDist,则证明A节点到B节点的距离最短,设置A节点为B节点父节点,并且长度修改为A节点的adjuDist加上边长。

否则不做操作。

5,等所有的节点初始化完了,从终止节点开始,通过终止节点的父节点找到上一个节点,输出节点的路径。

代码如下:

package 笔试题;

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);
} //此时该子节点的父节点和之前到该节点的最小长度已经知道了,则比较该边起始节点到该点的距离是否小于子节点的长度,
//只有小于的情况下,才更新该点为该子节点父节点,并且更新长度。
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 笔试题;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map; import 笔试题.Graph.Edge;
import 笔试题.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(0, 7);
}
}

运行结果:

[v1] to [v8] dijkstra shortest path :: [v1] --> [v2] --> [v5] --> [v8]
shortest length::25

Java邻接表表示加权有向图,附dijkstra最短路径算法的更多相关文章

  1. 数据结构(c++)(第二版) Dijkstra最短路径算法 教学示范代码出现重大问题!

    前言 去年在数据结构(c++)的Dijkstra教学算法案例中,发现了一个 bug 导致算法不能正常的运行,出错代码只是4行的for循环迭代代码. 看到那里就觉得有问题,但书中只给了关键代码的部分,其 ...

  2. 练习 Dijkstra 最短路径算法。

    练习 Dijkstra 最短路径算法. #coding: utf-8 # Author: woodfox, Oct 14, 2014 # http://en.wikipedia.org/wiki/Di ...

  3. Dijkstra 最短路径算法 秒懂详解

    想必大家一定会Floyd了吧,Floyd只要暴力的三个for就可以出来,代码好背,也好理解,但缺点就是时间复杂度高是O(n³). 于是今天就给大家带来一种时间复杂度是O(n²),的算法:Dijkstr ...

  4. 7-9 旅游规划(25 分)(Dijkstra最短路径算法)

    有了一张自驾旅游路线图,你会知道城市间的高速公路长度.以及该公路要收取的过路费.现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径.如果有若干条路径都是最短的,那么需要输出最便 ...

  5. Python 图_系列之纵横对比 Bellman-Ford 和 Dijkstra 最短路径算法

    1. 前言 因无向.无加权图的任意顶点之间的最短路径由顶点之间的边数决定,可以直接使用原始定义的广度优先搜索算法查找. 但是,无论是有向.还是无向,只要是加权图,最短路径长度的定义是:起点到终点之间所 ...

  6. Dijkstra最短路径算法[贪心]

    Dijkstra算法的标记和结构与prim算法的用法十分相似.它们两者都会从余下顶点的优先队列中选择下一个顶点来构造一颗扩展树.但千万不要把它们混淆了.它们解决的是不同的问题,因此,所操作的优先级也是 ...

  7. 一篇文章讲透Dijkstra最短路径算法

    Dijkstra是典型最短路径算法,计算一个起始节点到路径中其他所有节点的最短路径的算法和思想.在一些专业课程中如数据结构,图论,运筹学等都有介绍.其思想是一种基础的求最短路径的算法,通过基础思想的变 ...

  8. Dijkstra最短路径算法

    #include <iostream> #include <vector> #include <cstring> #include <cstdio> # ...

  9. Dijkstra最短路径算法实例

    #include <stdio.h>#include <stdlib.h>/* Dijkstra算法 */#define VNUM 5#define MV 65536int P ...

随机推荐

  1. [转]PHP SOCKET编程

    FROM : http://blog.csdn.net/hguisu/article/details/7448528 1. 预备知识 一直以来很少看到有多少人使用php的socket模块来做一些事情, ...

  2. asp.net 判断用户是否使用微信浏览器

    平时我们看一些网页的时候会发现这样的功能:有的页面只能在微信里访问,如果在电脑上访问就提示用户请到微信上访问该网页.这个用C#怎么实现呢?我们结合代码来看看. 首先,我们需要先判断用户使用的是什么浏览 ...

  3. 【UOJ Round #5】

    构造+贪心/数论 为什么只有两个标题呢……因为第二题我不会…… 怎样提高智商 构造题……然而一开始半天我都yy不出来…… 后来我想:这题应该不会特别麻烦,而且既然样例只给了1,可能再给大一点就让人发现 ...

  4. JSON与XML的区别比较(转)

    原文链接:JSON与XML的区别比较 1.定义介绍 (1).XML定义扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以 ...

  5. Java NIO Channel to Channel Transfers

    In Java NIO you can transfer data directly from one channel to another, if one of the channels is a ...

  6. C#多线程写日志

    由于程序是3层架构的,所有多线程记录日志成了比较棘手的问题,以前还真就没有在意过写日志的问题,认为不过是写文件罢了~~!如今发现原来要实现文件共享,并且能够使多线程同时操作日志还不能相互冲突,真的很麻 ...

  7. 初识EntityFramework6【转】

    http://www.cnblogs.com/wujingtao/p/5401132.html 什么是EF? EF是一种ORM(Object-relational mapping)框架,它能把我们在编 ...

  8. json传输二进制的方案【转】

    本文转自:http://wiyi.org/binary-to-string.html json 是一种很简洁的协议,但可惜的是,它只能传递基本的数型(int,long,string等),但不能传递by ...

  9. 在OneNote中快速插入当前日期和时间

    做笔记,难免有时需要记录当时的时间,记住这个快捷键会让记笔记的效率提升一点. To insert the current date and time, press Alt+Shift+F. To in ...

  10. Centos 7 开放查看端口 防火墙关闭打开

    Centos 7 firewall 命令: 查看已经开放的端口: firewall-cmd --list-ports 开启端口 firewall-cmd --zone=public --add-por ...