DiJkstra(狄克斯特拉)演算法
阿新 • • 發佈:2021-08-13
是從一個頂點到其餘各頂點的最短路徑演算法,解決的是有權圖中最短路徑問題。
迪傑斯特拉演算法主要特點是從起始點開始,採用貪心演算法的策略,每次遍歷到始點距離最近且未訪問過的頂點的鄰接節點,直到擴充套件到終點為止。
要求:圖中不能有累加和為負數的環
思路:
程式碼:
package Algorithms.Graph; import java.util.HashMap; import java.util.HashSet; import java.util.Map.Entry; public class Dijkstra { //獲取從head出發到所有點的最小距離 public staticHashMap<Node, Integer> dijkstra1(Node head) { //所有的距離指的是從唯一的源頭(head)到當前點的最小距離 // key:從head出發到達key // value:從head出發到達key的最小距離 //如果在表中沒有T的記錄,含義是從head出發到T這個點的距離為正無窮 HashMap<Node, Integer> distanceMap = new HashMap<>(); distanceMap.put(head, 0);//把從head到head的最小距離0加入distanceMap中//selectedNodes用於存放已經求過距離的節點,以後再不不碰 HashSet<Node> selectedNodes = new HashSet<>(); //得到一個距離最小的點A Node minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedNodes); while (minNode != null) { int distance = distanceMap.get(minNode); //計算最小距離 for(Edge edge : minNode.edges) { //迴圈點A的所有邊 Node toNode = edge.to; //邊所對應的點X if (!distanceMap.containsKey(toNode)) { //如果點X不在distanceMap中 distanceMap.put(toNode, distance + edge.weight); //在distanceMap中記錄從head到X點的距離 } else { //如果X在distanceMap中,更新最小距離 distanceMap.put(toNode, Math.min(distanceMap.get(toNode), distance + edge.weight)); } } selectedNodes.add(minNode); //把點A新增到已經求過距離的節點 //再次得到distanceMap中距離最小的節點B,然後重複以上操作, minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedNodes); // 最後所有的點都會進入selectedNode,minNode就會為null,退出迴圈,返回distanceMap } return distanceMap; } //在distanceMap選擇最小距離的節點,但不能是已經選過的點selectedNode public static Node getMinDistanceAndUnselectedNode(HashMap<Node, Integer> distanceMap, HashSet<Node> selectedNode) { Node minNode = null; int minDistance = Integer.MAX_VALUE; //到每點距離預設為系統最大值 for (Entry<Node, Integer> entry : distanceMap.entrySet()) { //遍歷distanceMap Node node = entry.getKey(); //取當前節點 int distance = entry.getValue(); //取當前節點所對應的距離 //如果這個Node不在已經求過節點的集合中且這個距離比當前最小距離小 if (!selectedNode.contains(node) && distance < minDistance) { minNode = node; //更新最小距離的節點 minDistance = distance; //更新最小距離 } } return minNode; } }
package Algorithms.Graph; import java.util.HashMap; public class Dijkstra { public static class NodeRecord { public Node node; public int distance; public NodeRecord(Node node, int distance) { this.node = node; this.distance = distance; } } public static class NodeHeap { private Node[] nodes; private HashMap<Node, Integer> heapIndexMap; private HashMap<Node, Integer> distanceMap; private int size; public NodeHeap(int size) { nodes = new Node[size]; heapIndexMap = new HashMap<>(); distanceMap = new HashMap<>(); this.size = 0; } public boolean isEmpty() { return size == 0; } public void addOrUpdateOrIgnore(Node node, int distance) { if (inHeap(node)) { distanceMap.put(node, Math.min(distanceMap.get(node), distance)); insertHeapify(node, heapIndexMap.get(node)); } if (!isEntered(node)) { nodes[size] = node; heapIndexMap.put(node, size); distanceMap.put(node, distance); insertHeapify(node, size++); } } public NodeRecord pop() { NodeRecord nodeRecord = new NodeRecord(nodes[0], distanceMap.get(nodes[0])); swap(0, size - 1); heapIndexMap.put(nodes[size - 1], -1); distanceMap.remove(nodes[size - 1]); nodes[size - 1] = null; heapify(0, --size); return nodeRecord; } private void insertHeapify(Node node, int index) { while (distanceMap.get(nodes[index]) < distanceMap.get(nodes[(index - 1) / 2])) { swap(index, (index - 1) / 2); index = (index - 1) / 2; } } private void heapify(int index, int size) { int left = index * 2 + 1; while (left < size) { int smallest = left + 1 < size && distanceMap.get(nodes[left + 1]) < distanceMap.get(nodes[left]) ? left + 1 : left; smallest = distanceMap.get(nodes[smallest]) < distanceMap.get(nodes[index]) ? smallest : index; if (smallest == index) { break; } swap(smallest, index); index = smallest; left = index * 2 + 1; } } private boolean isEntered(Node node) { return heapIndexMap.containsKey(node); } private boolean inHeap(Node node) { return isEntered(node) && heapIndexMap.get(node) != -1; } private void swap(int index1, int index2) { heapIndexMap.put(nodes[index1], index2); heapIndexMap.put(nodes[index2], index1); Node tmp = nodes[index1]; nodes[index1] = nodes[index2]; nodes[index2] = tmp; } } public static HashMap<Node, Integer> dijkstra2(Node head, int size) { NodeHeap nodeHeap = new NodeHeap(size); nodeHeap.addOrUpdateOrIgnore(head, 0); HashMap<Node, Integer> result = new HashMap<>(); while (!nodeHeap.isEmpty()) { NodeRecord record = nodeHeap.pop(); Node cur = record.node; int distance = record.distance; for (Edge edge : cur.edges) { nodeHeap.addOrUpdateOrIgnore(edge.to, edge.weight + distance); } result.put(cur, distance); } return result; } }優化