Java 迪杰斯特拉算法实现查找最短距离
迪杰斯特拉算法
迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。具体的计算规则我们可以通过下图进行查看。

通过这幅图我们可以简单的理解迪杰斯特拉算法算法的基础思路,下面我们就通过JAVA来实现这个算法。
算法实现
在迪杰斯特拉算法中我们需要保存从起点开始到每一个节点最短步长,这也是图中需要比较得出的步长,同时我们还需要存储该步长下的前一个节点是哪个,这样我们就可以通过终点一个一个往前推到起点,这样就出来了完整的最优路径。
每一个节点的最优前一节点
public class PreNode {
	private String preNodeName;//最优的前一个节点
	private int nodeStep;// 起点到前一个节点的步长+前一个节点本身的步长
	public PreNode(String preNodeName, int nodeStep) {
		this.preNodeName = preNodeName;
		this.nodeStep = nodeStep;
	}
	public String getPreNodeName() {
		return preNodeName;
	}
	public void setPreNodeName(String preNodeName) {
		this.preNodeName = preNodeName;
	}
	public int getNodeStep() {
		return nodeStep;
	}
	public void setNodeStep(int nodeStep) {
		this.nodeStep = nodeStep;
	}
}
定义返回的数据结构
package dijkstra;
import java.util.List;
public class MinStep {
	private boolean reachable;// 是否可达
	private int minStep;// 最短步长
	private List<String> step;// 最短路径
	public MinStep() {
	}
	public MinStep(boolean reachable, int minStep) {
		this.reachable = reachable;
		this.minStep = minStep;
	}
	public boolean isReachable() {
		return reachable;
	}
	public void setReachable(boolean reachable) {
		this.reachable = reachable;
	}
	public int getMinStep() {
		return minStep;
	}
	public void setMinStep(int minStep) {
		this.minStep = minStep;
	}
	public List<String> getStep() {
		return step;
	}
	public void setStep(List<String> step) {
		this.step = step;
	}
}
定义接口
package dijkstra;
import java.util.HashMap;
public interface Distance {
	public static final MinStep UNREACHABLE = new MinStep(false, -1);
	/**
	 * @param start
	 * @param end
	 * @param stepLength
	 * @return
	 * @Description: 起点到终点的最短路径
	 */
	public MinStep getMinStep(String start, String end, final HashMap<String, HashMap<String, Integer>> stepLength);
}
功能实现
package dijkstra;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map.Entry;
public class DistanceDijkstraImpl implements Distance {
	// 图中相邻两个节点的距离
	private HashMap<String, HashMap<String, Integer>> stepLength;
	// 非独立节点个数
	private int nodeNum;
	// 移除节点
	private HashSet<String> outNode;
	// 起点到各点的步长,key为目的节点,value为到目的节点的步长
	private HashMap<String, PreNode> nodeStep;
	// 下一次计算的节点
	private LinkedList<String> nextNode;
	// 起点、终点
	private String startNode;
	private String endNode;
	/**
	 * @param start
	 * @param end
	 * @param stepLength
	 * @return
	 * @Description: start 到 end 的最短距离
	 */
	public MinStep getMinStep(String start, String end, final HashMap<String, HashMap<String, Integer>> stepLength) {
		this.stepLength = stepLength;
		this.nodeNum = this.stepLength != null ? this.stepLength.size() : 0;
		// 起点、终点不在目标节点内,返回不可达
		if (this.stepLength == null || (!this.stepLength.containsKey(start)) || (!this.stepLength.containsKey(end))) {
			return UNREACHABLE;
		}
		initProperty(start, end);
		step();
		if (nodeStep.containsKey(end)) {
			return changeToMinStep();
		}
		return UNREACHABLE;
	}
	/**
	 * 返回最短距离以及路径
	 */
	private MinStep changeToMinStep() {
		MinStep minStep = new MinStep();
		minStep.setMinStep(nodeStep.get(endNode).getNodeStep());
		minStep.setReachable(true);
		LinkedList<String> step = new LinkedList<String>();
		minStep.setStep(step);
		// 先将终点添加到路径第一位中
		String tempNode = endNode;
		step.addFirst(tempNode);
		// 再将所经过的节点添加到路径第一位中
		while (nodeStep.containsKey(tempNode)) {
			PreNode preNode = nodeStep.get(tempNode);
			String preNodeName = preNode.getPreNodeName();
			// System.out.println(preNodeName + " " + preNode.getNodeStep());
			step.addFirst(preNodeName);
			tempNode = preNodeName;
		}
		return minStep;
	}
	/**
	 * @param start
	 * @Description: 初始化属性
	 */
	private void initProperty(String start, String end) {
		outNode = new HashSet<String>();
		nodeStep = new HashMap<String, PreNode>();
		nextNode = new LinkedList<String>();
		nextNode.add(start);
		startNode = start;
		endNode = end;
	}
	/**
	 * @param end
	 * @Description:
	 */
	private void step() {
		if (nextNode == null || nextNode.size() < 1) {
			return;
		}
		if (outNode.size() == nodeNum) {
			return;
		}
		// 获取下一个计算节点
		String start = nextNode.removeFirst();
		// 到达该节点的最小距离
		int step = 0;
		if (nodeStep.containsKey(start)) {
			step = nodeStep.get(start).getNodeStep();
		}
		// 获取该节点可达节点
		HashMap<String, Integer> nextStep = stepLength.get(start);
		Iterator<Entry<String, Integer>> iter = nextStep.entrySet().iterator();
		while (iter.hasNext()) {
			Entry<String, Integer> entry = iter.next();
			String key = entry.getKey();
			// 如果是起点到起点,不计算之间的步长
			if (key.equals(startNode)) {
				continue;
			}
			// 起点到可达节点的距离
			Integer value = entry.getValue() + step;
			if ((!nextNode.contains(key)) && (!outNode.contains(key))) {
				nextNode.add(key);
			}
			if (nodeStep.containsKey(key)) {
				// 比较步长
				if (value < nodeStep.get(key).getNodeStep()) {
					nodeStep.put(key, new PreNode(start, value));
				}
			} else {
				nodeStep.put(key, new PreNode(start, value));
			}
		}
		// 将该节点移除
		outNode.add(start);
		// 计算下一个节点
		step();
	}
}
step()逻辑解析
这一步也就是迪杰斯特拉算法的核心部分,在计算的过程中,我们需要进行如下步骤:
1)判断是否达到终止条件,如果达到终止条件,结束本次算法,如果没有达到,执行下一步;(终止条件:下一次需要计算的节点队列没有数据或已经计算过的节点数等于节点总数)
2)获取下一次计算的节点A;
3)从起点到各节点之间的最短距离map中获取到达A点的最小距离L;
4)获取A节点的可达节点B,计算从起点先到A再到B是否优于已有的其他方式到B,如果优于,则更新B节点,否则不更新;
5)判断B是否是已经移除的节点,如果不是移除的节点,把B添加到下一次需要计算的节点队列中,否则不做操作;
6)判断A节点是否还有除B以外的其他节点,如果有,执行第4)步,否则执行下一步;
7)将A节点从下一次需要计算的节点中移除添加到已经计算过的节点中;
8)执行第一步。
Demo运行
import java.util.HashMap;
import com.alibaba.fastjson.JSONObject;
public class DistanceTest {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HashMap<String, HashMap<String, Integer>> stepLength = new HashMap<String, HashMap<String, Integer>>();
		HashMap<String, Integer> step1 = new HashMap<String, Integer>();
		stepLength.put("1", step1);
		step1.put("2", 2);
		HashMap<String, Integer> step2 = new HashMap<String, Integer>();
		stepLength.put("2", step2);
		step2.put("1", 2);
		step2.put("3", 1);
		HashMap<String, Integer> step3 = new HashMap<String, Integer>();
		stepLength.put("3", step3);
		step3.put("2", 1);
		step3.put("4", 1);
		step3.put("9", 1);
		HashMap<String, Integer> step4 = new HashMap<String, Integer>();
		stepLength.put("4", step4);
		step4.put("5", 1);
		step4.put("3", 1);
		HashMap<String, Integer> step5 = new HashMap<String, Integer>();
		stepLength.put("5", step5);
		step5.put("4", 1);
		HashMap<String, Integer> step6 = new HashMap<String, Integer>();
		stepLength.put("6", step6);
		step6.put("9", 1);
		HashMap<String, Integer> step7 = new HashMap<String, Integer>();
		stepLength.put("7", step7);
		step7.put("10", 1);
		HashMap<String, Integer> step8 = new HashMap<String, Integer>();
		stepLength.put("8", step8);
		step8.put("11", 3);
		HashMap<String, Integer> step9 = new HashMap<String, Integer>();
		stepLength.put("9", step9);
		step9.put("3", 1);
		step9.put("6", 1);
		step9.put("10", 1);
		HashMap<String, Integer> step10 = new HashMap<String, Integer>();
		stepLength.put("10", step10);
		step10.put("9", 1);
		step10.put("7", 1);
		step10.put("11", 1);
		HashMap<String, Integer> step11 = new HashMap<String, Integer>();
		stepLength.put("11", step11);
		step11.put("8", 3);
		step11.put("10", 1);
		System.out.println(JSONObject.toJSON(stepLength));
		Distance distance = new DistanceDijkstraImpl();
		MinStep step = distance.getMinStep("1", "5", stepLength);
		System.out.println(JSONObject.toJSON(step));
		step = distance.getMinStep("1", "8", stepLength);
		System.out.println(JSONObject.toJSON(step));
		step = distance.getMinStep("8", "1", stepLength);
		System.out.println(JSONObject.toJSON(step));
		step = distance.getMinStep("11", "7", stepLength);
		System.out.println(JSONObject.toJSON(step));
		step = distance.getMinStep("10", "8", stepLength);
		System.out.println(JSONObject.toJSON(step));
	}
}
{“11”:{“8”:1,“10”:1},“1”:{“2”:2},“2”:{“1”:2,“3”:1},“3”:{“4”:1,“9”:1,“2”:1},“4”:{“5”:1,“3”:1},“5”:{“4”:1},“6”:{“9”:1},“7”:{“10”:1},“8”:{“11”:1},“9”:{“6”:1,“3”:1,“10”:1},“10”:{“11”:1,“9”:1,“7”:1}}
{“minStep”:5,“step”:[“1”,“2”,“3”,“4”,“5”],“reachable”:true}
{“minStep”:7,“step”:[“1”,“2”,“3”,“9”,“10”,“11”,“8”],“reachable”:true}
{“minStep”:7,“step”:[“8”,“11”,“10”,“9”,“3”,“2”,“1”],“reachable”:true}
{“minStep”:2,“step”:[“11”,“10”,“7”],“reachable”:true}
{“minStep”:2,“step”:[“10”,“11”,“8”],“reachable”:true}

Java 迪杰斯特拉算法实现查找最短距离的更多相关文章
- 最短路径之迪杰斯特拉算法的Java实现
		Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法.该算法被称为是“贪心算法”的成功典范.本文接下来将尝试以最通俗的语言来介绍这个伟大的算法,并赋予java实现代码. 一.知识准备 ... 
- 数据结构---公交线路提示系统05(内附读取表格+迪杰斯特拉算法Java代码)
		今天做的最多的事情就是纠错了,通过添加输出语句判断错误来源: 找到错误来源: wb = new XSSFWorkbook(input);//语句创建错误 网上查询发现是jar包的问题: 下图为poi的 ... 
- 迪杰斯特拉算法完整代码(Java)
		package com.rao.graph; import java.util.*; /** * @author Srao * @className Dijkstra * @date 2019/12/ ... 
- [从今天开始修炼数据结构]图的最短路径 —— 迪杰斯特拉算法和弗洛伊德算法的详解与Java实现
		在网图和非网图中,最短路径的含义不同.非网图中边上没有权值,所谓的最短路径,其实就是两顶点之间经过的边数最少的路径:而对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,我们称路径上第 ... 
- HDU6166-Senior Pan-Dijkstra迪杰斯特拉算法(添加超源点,超汇点)+二进制划分集合-2017多校Team09
		学长好久之前讲的,本来好久好久之前就要写题解的,一直都没写,懒死_(:з」∠)_ Senior Pan Time Limit: 12000/6000 MS (Java/Others) Memor ... 
- C# 迪杰斯特拉算法 Dijkstra
		什么也不想说,现在直接上封装的方法: using System; using System.Collections.Concurrent; using System.Collections.Gener ... 
- c/c++ 图的最短路径  Dijkstra(迪杰斯特拉)算法
		c/c++ 图的最短路径 Dijkstra(迪杰斯特拉)算法 图的最短路径的概念: 一位旅客要从城市A到城市B,他希望选择一条途中中转次数最少的路线.假设途中每一站都需要换车,则这个问题反映到图上就是 ... 
- HDU 3790(两种权值的迪杰斯特拉算法)
		传送门: http://acm.hdu.edu.cn/showproblem.php?pid=3790 最短路径问题 Time Limit: 2000/1000 MS (Java/Others) ... 
- 数据结构图之三(最短路径--迪杰斯特拉算法——转载自i=i++
		数据结构图之三(最短路径--迪杰斯特拉算法) [1]最短路径 最短路径?别乱想哈,其实就是字面意思,一个带边值的图中从某一个顶点到另外一个顶点的最短路径. 官方定义:对于内网图而言,最短路径是指两 ... 
随机推荐
- python实战,
			1.把日志状态码为200得请求记录下来 记录信息(ip,访问时间,请求资源) 封装函数再次调用,健壮性try except #coding=utf-8import redef aclog(path, ... 
- webpack 第二部分
			默认根目录 当前项目 修改目录 devServer devServer:{ open:true, //自动打开浏览器 port:3000, // 端口 contentBase:"dist&q ... 
- 从curl命令获取libcurl的用法
			libcurl的用法参数太多 有时候弄不好 可以先用curl命令实现了 然后获取相应的libcurl代码 比如要上传文件 curl -T d:/h.txt http://demo.xudp.cn/up ... 
- 8.进行图片的裁剪,同时使用resize将图片的维度进行变化
			1.img.crop((x1, y1, x2, y2)) 进行图片的裁剪 参数说明: x1, y1, x2, y2 表示图片的大小 2. img.resize((w, h)) # 进行图片的维度变化 ... 
- python问题笔记
			1.for...in...:和while...:循环末端都可以有一个else:语句,但他仅在循环不是由break语句退出时才会被运行 2.input raw input区别 一. 可以看到:这两个函数 ... 
- Not sending mail to unregistered use
			其实这个问题是Jenkins管理用户的一个问题,它可以自动从git或者svn读取用户信息以及邮件(如果git等中设置了的话), 但它不又不创建Jenkins上的用户,所以你可以在pepole列表上看到 ... 
- Centos 搭建DNS服务器
			1:安装DNS服务 yum install bind -y 2:修改/etc/named.conf 配置文件 listen-on port 53 { any; }; listen-on-v6 port ... 
- CMake下,某些选项的后调整
			编译安卓NDK库时,发现在R15的NDK编译出来的库,总是带了-g选项,导致附带调试,文件过大. 搜索一番后,结论是NDK的文件中有问题: https://github.com/android/ndk ... 
- 第 10 章  python进程与多进程
			一.背景知识 顾明思义,进程即正在执行的一个过程,进程是对正在云的程序的一个抽象. 进程的概念起源与操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一,操作系统的其他所 ... 
- Django开发—如何重置migration
			情景一:不需要原有的数据库数据 删除数据库所有的表删除项目的migration模块中的所有 文件,除了init.py 文件执行脚本 python3 manage.py makemigrations p ... 
