前言

  Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法。该算法被称为是“贪心算法”的成功典范。本文接下来将尝试以最通俗的语言来介绍这个伟大的算法,并赋予java实现代码。

一、知识准备:

  1、表示图的数据结构

  用于存储图的数据结构有多种,本算法中笔者使用的是邻接矩阵。

  图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息。

设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为:

  

从上面可以看出,无向图的边数组是一个对称矩阵。所谓对称矩阵就是n阶矩阵的元满足aij = aji。即从矩阵的左上角到右下角的主对角线为轴,右上角的元和左下角相对应的元全都是相等的。

从这个矩阵中,很容易知道图中的信息。

(1)要判断任意两顶点是否有边无边就很容易了;

(2)要知道某个顶点的度,其实就是这个顶点vi在邻接矩阵中第i行或(第i列)的元素之和;

(3)求顶点vi的所有邻接点就是将矩阵中第i行元素扫描一遍,arc[i][j]为1就是邻接点;

而有向图讲究入度和出度,顶点vi的入度为1,正好是第i列各数之和。顶点vi的出度为2,即第i行的各数之和。

  有向图的定义也类似,故不做赘述。

  2、单起点全路径

    所谓单起点全路径,就是指在一个图中,从一个起点出发,到所有节点的最短路径。

  3、图论的基本知识(读者需自行寻找相关资料)

  4、互补松弛条件

 设标量d1,d2,....,dN满足

    dj<=di + aij,  (i,j)属于A,

 且P是以i1为起点ik为终点的路,如果

    dj = di + aij, 对P的所有边(i, j)

 成立,那么P是从i1到ik的最短路。其中,满足上面两式的被称为最短路问题的互补松弛条件。

 

二、算法思想

  1、令G = (V,E)为一个带权无向图。G中若有两个相邻的节点,i和j。aij(在这及其后面都表示为下标,请注意)为节点i到节点j的权值,在本算法可以理解为距离。每个节点都有一个值di(节点标记)表示其从起点到它的某条路的距离。

  2、算法初始有一个数组V用于储存未访问节点的列表,我们暂称为候选列表。选定节点1为起始节点。开始时,节点1的d1=0, 其他节点di=无穷大,V为所有节点。
初始化条件后,然后开始迭代算法,直到V为空集时停止。具体迭代步骤如下:

   将d值最小的节点di从候选列表中移除。(本例中V的数据结构采用的是优先队列实现最小值出列,最好使用斐波那契对,在以前文章有过介绍,性能有大幅提示)。对于以该节点为起点的每一条边,不包括移除V的节点, (i, j)属于A, 若dj > di + aij(违反松弛条件),则令

  dj = di + aij    , (如果j已经从V中移除过,说明其最小距离已经计算出,不参与此次计算)

  可以看到在算法的运算工程中,节点的d值是单调不增的

  具体算法图解如下

  

三、java代码实现

  

public class Vertex implements Comparable<Vertex>{

    /**
* 节点名称(A,B,C,D)
*/
private String name; /**
* 最短路径长度
*/
private int path; /**
* 节点是否已经出列(是否已经处理完毕)
*/
private boolean isMarked; public Vertex(String name){
this.name = name;
this.path = Integer.MAX_VALUE; //初始设置为无穷大
this.setMarked(false);
} public Vertex(String name, int path){
this.name = name;
this.path = path;
this.setMarked(false);
} @Override
public int compareTo(Vertex o) {
return o.path > path?-1:1;
}
}
public class Graph {

    /*
* 顶点
*/
private List<Vertex> vertexs; /*
* 边
*/
private int[][] edges; /*
* 没有访问的顶点
*/
private Queue<Vertex> unVisited; public Graph(List<Vertex> vertexs, int[][] edges) {
this.vertexs = vertexs;
this.edges = edges;
initUnVisited();
} /*
* 搜索各顶点最短路径
*/
public void search(){
while(!unVisited.isEmpty()){
Vertex vertex = unVisited.element();
//顶点已经计算出最短路径,设置为"已访问"
  vertex.setMarked(true);
//获取所有"未访问"的邻居
  List<Vertex> neighbors = getNeighbors(vertex);
//更新邻居的最短路径
updatesDistance(vertex, neighbors);
pop();
}
System.out.println("search over");
} /*
* 更新所有邻居的最短路径
*/
private void updatesDistance(Vertex vertex, List<Vertex> neighbors){
for(Vertex neighbor: neighbors){
updateDistance(vertex, neighbor);
}
} /*
* 更新邻居的最短路径
*/
private void updateDistance(Vertex vertex, Vertex neighbor){
int distance = getDistance(vertex, neighbor) + vertex.getPath();
if(distance < neighbor.getPath()){
neighbor.setPath(distance);
}
} /*
* 初始化未访问顶点集合
*/
private void initUnVisited() {
unVisited = new PriorityQueue<Vertex>();
for (Vertex v : vertexs) {
unVisited.add(v);
}
} /*
* 从未访问顶点集合中删除已找到最短路径的节点
*/
private void pop() {
unVisited.poll();
} /*
* 获取顶点到目标顶点的距离
*/
private int getDistance(Vertex source, Vertex destination) {
int sourceIndex = vertexs.indexOf(source);
int destIndex = vertexs.indexOf(destination);
return edges[sourceIndex][destIndex];
} /*
* 获取顶点所有(未访问的)邻居
*/
private List<Vertex> getNeighbors(Vertex v) {
List<Vertex> neighbors = new ArrayList<Vertex>();
int position = vertexs.indexOf(v);
Vertex neighbor = null;
int distance;
for (int i = 0; i < vertexs.size(); i++) {
if (i == position) {
//顶点本身,跳过
continue;
}
distance = edges[position][i]; //到所有顶点的距离
if (distance < Integer.MAX_VALUE) {
//是邻居(有路径可达)
neighbor = getVertex(i);
if (!neighbor.isMarked()) {
//如果邻居没有访问过,则加入list;
neighbors.add(neighbor);
}
}
}
return neighbors;
} /*
* 根据顶点位置获取顶点
*/
private Vertex getVertex(int index) {
return vertexs.get(index);
} /*
* 打印图
*/
public void printGraph() {
int verNums = vertexs.size();
for (int row = 0; row < verNums; row++) {
for (int col = 0; col < verNums; col++) {
if(Integer.MAX_VALUE == edges[row][col]){
System.out.print("X");
System.out.print(" ");
continue;
}
System.out.print(edges[row][col]);
System.out.print(" ");
}
System.out.println();
}
}
}

    

public class Test {

    public static void main(String[] args){
List<Vertex> vertexs = new ArrayList<Vertex>();
Vertex a = new Vertex("A", 0);
Vertex b = new Vertex("B");
Vertex c = new Vertex("C");
Vertex d = new Vertex("D");
Vertex e = new Vertex("E");
Vertex f = new Vertex("F");
vertexs.add(a);
vertexs.add(b);
vertexs.add(c);
vertexs.add(d);
vertexs.add(e);
vertexs.add(f);
int[][] edges = {
{Integer.MAX_VALUE,6,3,Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MAX_VALUE},
{6,Integer.MAX_VALUE,2,5,Integer.MAX_VALUE,Integer.MAX_VALUE},
{3,2,Integer.MAX_VALUE,3,4,Integer.MAX_VALUE},
{Integer.MAX_VALUE,5,3,Integer.MAX_VALUE,5,3},
{Integer.MAX_VALUE,Integer.MAX_VALUE,4,5,Integer.MAX_VALUE,5},
{Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MAX_VALUE,3,5,Integer.MAX_VALUE} };
Graph graph = new Graph(vertexs, edges);
graph.printGraph();
graph.search();
} }

四、 推荐阅读

  网络最大流问题之Ford-Fulkerson算法图文详解

 

最短路径算法之Dijkstra算法(java实现)的更多相关文章

  1. 单源最短路径问题2 (Dijkstra算法)

    用邻接矩阵 /* 单源最短路径问题2 (Dijkstra算法) 样例: 5 7 0 1 3 0 3 7 1 2 4 1 3 2 2 3 5 2 4 6 3 4 4 输出: [0, 3, 7, 5, 9 ...

  2. 最短路径算法(Dijkstra算法、Floyd-Warshall算法)

    最短路径算法具体的形式包括: 确定起点的最短路径问题:即已知起始结点,求最短路径的问题.适合使用Dijkstra算法. 确定终点的最短路径问题:即已知终结结点,求最短路径的问题.在无向图中,该问题与确 ...

  3. C++编程练习(11)----“图的最短路径问题“(Dijkstra算法、Floyd算法)

    1.Dijkstra算法 求一个顶点到其它所有顶点的最短路径,是一种按路径长度递增的次序产生最短路径的算法. 算法思想: 按路径长度递增次序产生算法: 把顶点集合V分成两组: (1)S:已求出的顶点的 ...

  4. 最短路径问题的Dijkstra算法

      问题 最短路径问题的Dijkstra算法 是由荷兰计算机科学家艾兹赫尔·戴克斯特拉提出.迪科斯彻算法使用了广度优先搜索解决非负权有向图的单源最短路径问题,算法终于得到一个最短路径树>    ...

  5. 【算法】Dijkstra算法(单源最短路径问题)(路径还原) 邻接矩阵和邻接表实现

    Dijkstra算法可使用的前提:不存在负圈. 负圈:负圈又称负环,就是说一个全部由负权的边组成的环,这样的话不存在最短路,因为每在环中转一圈路径总长就会边小. 算法描述: 1.找到最短距离已确定的顶 ...

  6. 算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法

    一.名称 动态规划法应用 二.目的 1.贪婪技术的基本思想: 2.学会运用贪婪技术解决实际设计应用中碰到的问题. 三.要求 1.实现基于贪婪技术思想的Prim算法: 2.实现基于贪婪技术思想的Dijk ...

  7. 数据结构与算法系列研究七——图、prim算法、dijkstra算法

    图.prim算法.dijkstra算法 1. 图的定义 图(Graph)可以简单表示为G=<V, E>,其中V称为顶点(vertex)集合,E称为边(edge)集合.图论中的图(graph ...

  8. Prim算法、Kruskal算法、Dijkstra算法

    无向加权图 1.生成树(minimum spanning trees) 图的生成树是它一棵含有所有顶点的无环联通子图 最小生成树:生成树中权值和最小的(所有边的权值之和) Prim算法.Kruskal ...

  9. 单源最短路径问题之dijkstra算法

    欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 1. 算法的原理 以源点开始,以源点相连的顶点作为向外延伸的顶点,在所有这些向外延伸的顶 ...

随机推荐

  1. Handler与Looper,MessageQueue的关系

    总结一下Handler与Looper,MessageQueue的关系,并实现自定义与子线程相关的Handler. 一.Handler与Looper,MessageQueue的关系 它们之间的关系其实就 ...

  2. olacle数据库员工表的创建,及插入数据,添加约束,删除列,查询数据的sql语句

    ---删除原有的员工表drop TABLE employee;---创建员工表CREATE TABLE employee       (       empno NUMBER(4) NOT NULL, ...

  3. 问题解决——XP线程池找不到QueueUserWorkItem

    2013年7月11号 主管让同事写一个并发100的小工具进行什么压力测试,据说是创建100个线程. 我表示这真真的是在坑人! 线程创建消耗资源,以自己的笔记本来跑这个东西,时间片都消耗在了线程切换上了 ...

  4. SQLPLUS连接oracle

    SQLPlus 在连接时通常有三种方式 1. sqlplus / as sysdba 操作系统认证,不需要数据库服务器启动listener,也不需要数据库服务器处于可用状态.比如我们想要启动数据库就可 ...

  5. linux命令后台运行

    有两种方式: 1. command & : 后台运行,你关掉终端会停止运行    2. nohup command & : 后台运行,你关掉终端也会继续运行 一. 简介     Lin ...

  6. dev/shm time in linux

    统计文件夹大小: du -hx --max=1 : du -sk :du -hsc 重新组织行分隔符进行显示: echo "abc,dd,bach,dong,jing,shang,china ...

  7. 有限状态机HDL模板

    逻辑设计, 顾名思义, 只要理清了逻辑和时序, 剩下的设计只是做填空题而已. 下面给出了有限状态机的标准设计,分别为 VHDL 和 Verilog 代码 1  有限状态机 2  VHDL模板之一 li ...

  8. JAVASE笔记回顾

    第一部分,JAVA基础和面向对象 part01 入门与开发环境搭建 1: 计算机基础知识(了解)(1)计算机(2)计算机硬件(3)计算机软件系统软件:windows,linux,mac应用软件:QQ, ...

  9. (转)对各种初始化函数的理解:OnInitDialog、InitInstance、InitApplication函数的理解

    InitInstance和InitApplication 是 APP 类的初始化.而 OnInitDialog 是在 Dialog 类初始化时调用的函数. ★ 应用程序相关配置,一般在InitInst ...

  10. WinCE应用程序崩溃提示框的处理

    WinCE的开发人员和WinCE设备的用户应该对下面这两个错误不陌生,"Application encountered a serious error and must shut down& ...