您的位置:首页 > 其它

Dijkstra最短路径算法

2017-10-27 18:03 423 查看
        Dijkstra最短路径算法是一种单源最短路径算法,该算法要求路径上任意两点间路径为非负权边。用于计算从路径中指定的顶点到其他所有的顶点的最短路径。所以广泛应用于能够建模为图的问题中,用以查找两个节点最短路径。

  
算法实现原理

        从最小的子路径开始(只包含一个顶点A1),遍历添加其他顶点(Ai)到子路径中,每次重新计算起始点到其他顶点的最短距离(只影响到与Ai相连的顶点),直到所有顶点加入到路径中。

  
与贪心算法、动态规划比较

  Dijkstra算法是个广度搜索的算法。实现的原理与动态规划、贪心算法都有一些共同点,又不完全一样。比较如下:

 类同点不同点
贪心算法1、都是从最小的子问题开始递推到整个问题。

2、也用到贪心策略(每一步计算局部最优解为最短路径)。
1、可以计算全局最优解,而贪心算法只能计算局部最优解。

2、计算过程中,不会对子问题结果进行纠正。
动态规划1、都是从最小的子问题开始递推到整个问题。1、遇到重复子问题,不会重新计算,直接引用结果,同样不会对子问题结果进行纠正。
代码实现



以上图为例子,java实现如下:

package algorithm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class DijkstraTest {

/**
* 路径中结点名
*/
private static final String[] nodeNameArr = { "A", "B", "C", "D", "E", "F" };

/**
* 路径中各结点到其他结点的路径权矩阵,-1表示不可达
*/
private static final int[][] pathMatrix = { { 0, 6, 3, -1, -1, -1 }, { 6, 0, 2, 5, -1, -1 }, { 3, 2, 0, 3, 4, -1 },
{ -1, 5, 3, 0, 2, 3 }, { -1, -1, 4, 2, 0, 5 }, { -1, -1, -1, 3, 5, 0 } };

public static void main(String[] args) {
Map<String, Node> nodeMap = generateNetwork(nodeNameArr, pathMatrix);
DijkstraPath dijkstraPath = dijkstra(nodeMap, "A");
System.out.println(dijkstraPath);
}

/**
* 根据结点名称,路径矩阵,生成结点网络
*
* @param nodeNameArr
* @param pathMatrix
* @return
*/
public static Map<String, Node> generateNetwork(String[] nodeNameArr, int[][] pathMatrix) {
Node[] nodes = new Node[nodeNameArr.length];
Map<String, Node> nodeMap = new HashMap<>();
for (int i = 0; i < nodeNameArr.length; i++) {
nodes[i] = new Node(nodeNameArr[i]);
nodeMap.put(nodeNameArr[i], nodes[i]);
}

for (int i = 0; i < nodes.length; i++) {
Node node = nodes[i];
int[] nodePath = pathMatrix[i];
Set<Path> pathes = new HashSet<>();
node.setPathes(pathes);
for (int j = 0; j < nodePath.length; j++) {
if (nodePath[j] > 0) {
Path path = new Path();
path.setDistance(nodePath[j]);
path.setStartNode(node);
path.setEndNode(nodes[j]);
pathes.add(path);
}
}
}

return nodeMap;
}

/**
* 在结点网络中,使用dijkstra算法,计算出rNode到其他结点的最小距离
*
* @param nodeMap
* @param rNode
*/
public static DijkstraPath dijkstra(Map<String, Node> nodeMap, String rNode) {
Set<Node> calcSet = new HashSet<>();
Set<Node> restSet = new HashSet<>();
for (Map.Entry<String, Node> entry : nodeMap.entrySet()) {
if (rNode.equals(entry.getKey())) {
calcSet.add(entry.getValue());
} else {
restSet.add(entry.getValue());
}
}

DijkstraPath dijkstraPath = new DijkstraPath(nodeMap.get(rNode));
Map<String, MultiPath> pathMap = new HashMap<>();
for (Node node : restSet) {
MultiPath multiPath = new MultiPath();
multiPath.setDistance(-1);
multiPath.setStartNode(dijkstraPath.getStartNode());
multiPath.setEndNode(node);
multiPath.setPath(new ArrayList<Path>());

pathMap.put(node.getName(), multiPath);
dijkstraPath.addPath(multiPath);
}

//		Node node = dijkstraPath.getStartNode();

//		Set<Path> pathList = node.getPathes();

calcChildernNodePath(pathMap, null, calcSet);

return dijkstraPath;
}

/**
* 广度遍历处理新加入端点,计算最短路径
* @param pathMap
* @param handledSet
* @param newAddNodes
*/
private static void calcChildernNodePath(Map<String, MultiPath> pathMap, Set<Node> handledSet, Set<Node> newAddNodes) {
if (null == handledSet) {
handledSet = new HashSet<>();
}
if (null == newAddNodes || newAddNodes.size() == 0) {
return;
}

// 遍历处理新加入集合的子结点
for (Node node : newAddNodes) {
MultiPath curMultiPath = pathMap.get(node.getName());
for (Path path : node.getPathes()) {
MultiPath multiPath = pathMap.get(path.getEndNode().getName());
if (null != multiPath) {
if (multiPath.getDistance() <= 0) {// 还未设置最短距离
List<Path> pathes = new ArrayList<>();
if (null == curMultiPath) {//未找到,说明是开始结点,即node=rootNode
multiPath.setDistance(path.getDistance());
} else {
multiPath.setDistance(curMultiPath.getDistance() + path.getDistance());
pathes.addAll(curMultiPath.getPathes());
}
pathes.add(path);
multiPath.setPath(pathes);
} else {
int min = curMultiPath.getDistance() + path.getDistance();
if (min < multiPath.getDistance()) {
List<Path> pathes = new ArrayList<>(curMultiPath.getPathes());
pathes.add(path);
multiPath.setPath(pathes);
multiPath.setDistance(min);
}
}
}
}
handledSet.add(node);
}
Set<Node> nodeSet = new HashSet<>();
for (Node node : newAddNodes) {
// 递归计算子结点
for (Path path : node.getPathes()) {
if (!handledSet.contains(path.getEndNode())) {
nodeSet.add(path.getEndNode());
}
}
}
calcChildernNodePath(pathMap, handledSet, nodeSet);
}
}

class DijkstraPath {
private Node startNode;
private Set<MultiPath> pathSet = new HashSet<>();

public DijkstraPath(Node node) {
this.startNode = node;
}

public Node getStartNode() {
return startNode;
}

public void setStartNode(Node startNode) {
this.startNode = startNode;
}

public Set<MultiPath> getPathSet() {
return pathSet;
}

//	public void setPathSet(Set<MultiPath> pathSet) {
//		this.pathSet = pathSet;
//	}

public void addPath(MultiPath path) {
pathSet.add(path);
}

public void removePath(MultiPath path) {
pathSet.remove(path);
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
for (MultiPath multiPath : pathSet) {
builder.append(multiPath).append('\n');
}
return builder.toString();
}
}

class MultiPath extends Path {
private List<Path> pathes;

public List<Path> getPathes() {
return pathes;
}

public void setPath(List<Path> pathes) {
this.pathes = pathes;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder().append(getStartNode()).append("->").append(getEndNode()).append(":")
.append(getStartNode());

for (Path path : pathes) {
builder.append("->").append(path.getEndNode());
}

return builder.append("[").append(getDistance()).append("]").toString();
}
}

class Node {
private String name;// 结点名
private Set<Path> pathes;// 结点可达路径

public Node(String name) {
super();
this.name = name;
}

public Set<Path> getPathes() {
return pathes;
}

public void setPathes(Set<Path> pathes) {
this.pathes = pathes;
}

public String getName() {
return name;
}

@Override
public String toString() {
return name;
}
}

class Path {
private Node startNode;// 路径起始结点
private Node endNode;// 路径结束结点
private int distance;// 路径权值

public Node getStartNode() {
return startNode;
}

public void setStartNode(Node startNode) {
this.startNode = startNode;
}

public Node getEndNode() {
return endNode;
}

public void setEndNode(Node endNode) {
this.endNode = endNode;
}

public int getDistance() {
return distance;
}

public void setDistance(int distance) {
this.distance = distance;
}

@Override
public String toString() {
return String.format("%s->%s[%d]", startNode, endNode, distance);
}
}

执行结果:

A->C:A->C[3]
A->B:A->C->B[5]
A->E:A->C->E[7]
A->D:A->C->D[6]
A->F:A->C->D->F[9]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dijkstra 算法