import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; public class Test40 { //点的定义 public static class Node{ public int value;//点上的值也就是编号 public int in;//进去的边有多少 public int out;//出去的边有多少 public ArrayList<Node> nexts;//直接邻居,由自己出发能到达的点 public ArrayList<Edge> edges;//边的集合 public Node(int value){ this.value =value; in =0; out =0; nexts = new ArrayList<>(); edges = new ArrayList<>(); } } //边的定义 public static class Edge{ public int weight;//权重 public Node from; public Node to; public Edge(int weight , Node from , Node to){ this.weight = weight; this.from = from; this.to = to; } } //图的定义 public static class Graph{ public HashMap<Integer ,Node> nodes;//编号为多少的点那个点的结构是什么 public HashSet<Edge> edges;//所有的边装在边集里 public Graph(){ nodes = new HashMap<>(); edges = new HashSet<>(); } } //形成图结构 //传进来二维数组,每行有三个值,分别为权重,from和to这三个属性代表了每个点的结构 public static Graph createGraph(Integer[][] matrix) { Graph graph = new Graph(); for (int i = 0; i < matrix.length; i++) { //建立数据 Integer weight = matrix[i][0]; Integer from = matrix[i][1]; Integer to = matrix[i][2]; //如果图里没有from这个点,就新建 if (!graph.nodes.containsKey(from)) { graph.nodes.put(from, new Node(from)); } //如果图里没有to这个点,就新建 if (!graph.nodes.containsKey(to)) { graph.nodes.put(to, new Node(to)); } //起始点和出发点 Node fromNode = graph.nodes.get(from); Node toNode = graph.nodes.get(to); //表达边 Edge newEdge = new Edge(weight, fromNode, toNode); fromNode.nexts.add(toNode); fromNode.out++; toNode.in++; fromNode.edges.add(newEdge); graph.edges.add(newEdge); } return graph; } 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; } //节点记录 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 int size; //如果一个节点在堆上,就记录它的index private HashMap<Node , Integer> heapIndexMap; //从源节点出发到该节点的最小距离 private HashMap<Node , Integer> distanceMap; public NodeHeap(int size){ nodes = new Node[size]; heapIndexMap = new HashMap<>(); distanceMap = new HashMap<>(); size = 0; } //判断堆是否空了 public boolean isEmpty(){ return size == 0; } public void addOrUpdateOrIgnore(Node node , int distance){ //如果node在堆上 if(inHeap(node)){ //那么就在distanceMap中把它的老记录和新记录取最小值再存进去 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){ //节点进来过且堆上的值不为-1 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 temp = nodes[index1]; nodes[index1] = nodes[index2]; nodes[index2] = temp; } } }
堆优化后的dijkstra算法
于 2024-08-10 23:24:32 首次发布