Dijkstra最短路径算法
2017-10-27 18:03
423 查看
Dijkstra最短路径算法是一种单源最短路径算法,该算法要求路径上任意两点间路径为非负权边。用于计算从路径中指定的顶点到其他所有的顶点的最短路径。所以广泛应用于能够建模为图的问题中,用以查找两个节点最短路径。
算法实现原理
从最小的子路径开始(只包含一个顶点A1),遍历添加其他顶点(Ai)到子路径中,每次重新计算起始点到其他顶点的最短距离(只影响到与Ai相连的顶点),直到所有顶点加入到路径中。
与贪心算法、动态规划比较
Dijkstra算法是个广度搜索的算法。实现的原理与动态规划、贪心算法都有一些共同点,又不完全一样。比较如下:
代码实现
以上图为例子,java实现如下:
执行结果:
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]
算法实现原理
从最小的子路径开始(只包含一个顶点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's 最短路径算法能不能解这个含有负权重的问题
- Dijkstra(迪杰斯特拉)最短路径算法分析
- dijkstra 最短路径算法
- 最短路径之迪克斯特拉(Dijkstra)算法
- 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
- 数据结构与算法--单源最短路径算法之dijkstra
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 网格最短路径算法(Dijkstra & Fast Marching)
- 最短路径(Dijkstra)算法 之 .Net 4.0 Parallel 实现
- 网络中两点最短路径 Dijkstra 算法
- 贪心算法 Dijkstra 单源最短路径
- PHP实现的迪科斯彻(Dijkstra)最短路径算法实例
- 最短路径算法——Dijkstra and Floyd算法
- 算法 单源最短路径Dijkstra
- dijkstra 求最短路径算法
- Dijkstra/Floyd-Warshall 最短路径算法
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- Dijkstra算法求单源最短路径
- 《算法导论》读书笔记之图论算法—Dijkstra 算法求最短路径
- 单源最短路径算法模板(Dijkstra+BellmanFrod)