Direxlas Algorithmus – Optimierung

Im vorherigen Direxla-Algorithmus wurde die Funktion implementiert und die Erfassung der kürzesten Entfernung aller erreichbaren Punkte vom Quellpunkt im Atlas abgeschlossen.
Die Implementierung der getMinDistanceAndUnSelectNode()-Methode im Code ist jedoch nicht präzise: Jedes Mal, wenn der minNode abgerufen wird, muss die gesamte Karte durchlaufen werden, und die zeitliche Komplexität ist zu hoch. Dieser Artikel ist hauptsächlich eine Optimierung für den Code des vorherigen Artikels.
Der Optimierungsprozess verwendet hauptsächlich die Datenstruktur des erweiterten Heaps . Wenn Sie es nicht verstehen, wird dringend empfohlen, sich die spezifische Implementierung des erweiterten Heaps anzusehen .

Rezension:

Fügen Sie hier eine Bildbeschreibung ein
Im vorherigen Artikel wurden die festen Punkte in den Satz eingefügt, die Abstandsbeziehung zwischen jedem Punkt in die Karte eingefügt und der minimale minNode jedes Mal durch Durchlaufen der Karte ermittelt und alle Kanten gemäß diesem Punkt gefunden Berechnen Sie den Mindestabstand, geben Sie ihn ein und bestimmen Sie schließlich den Mindestabstand in der Tabelle.

Optimieren Sie
die Verwendung erweiterter Heaps, um die Beziehung zwischen Punkten und Abständen aufrechtzuerhalten, und nutzen Sie die Vorteile kleiner Root-Heaps, um den kleinsten Punkt oben zu halten. Es ist zu beachten, dass dieses Element in den vorherigen erweiterten Heaps entfernt wird wird direkt entfernt, aber Sie können es hier nicht entfernen, da aufgezeichnet werden muss, ob sich dieser Punkt auf dem Heap befindet und ob er dem Heap hinzugefügt wurde. Daher sollte der Wert für das bestimmte Element auf -1 geändert werden, um dies zu kennzeichnen Das aktuelle Element wurde bestimmt und muss nicht verschoben werden.

Verbesserter Heap-Code
Die distanceMap in NodeHeap wird verwendet, um die Beziehung zwischen Punkten und Entfernungen darzustellen, und die oberen Elemente des Heaps werden entsprechend der Größe des Werts dynamisch geändert.
Die Hauptmethode ist addOrUpdateOrIgnore().
Wenn sich das aktuelle Element im Heap befindet und der Wert! = 1 (inHeap) ist, bedeutet dies, dass das Element nicht bestimmt wurde. Beurteilen Sie dann, ob der eingehende Knoten und der Wert größer als der Wert sind, der dem Knoten im aktuellen Heap entspricht Nehmen Sie ein kleines Update vor. Wenn es aktualisiert wird, muss es geändert werden Die Position des Elements im Heap, da nur eine Aktualisierung und Verkleinerung möglich ist. Rufen Sie also die Methode insertHeapify auf, um die Heap-Struktur zu ändern.
Wenn das Element nicht zum Heap hinzugefügt wurde (!isEntered), hängt es am Ende des Heaps und insertHeapify prüft, ob es nach oben verschoben wurde.
Wenn in der Pop-Methode der Heap gepoppt wird, wird er normalerweise gelöscht, kann aber nicht gelöscht werden. Mit Ausnahme des Austauschs mit dem letzten Element und der Verschiebung nach unten ändern Sie den entsprechenden Wert in der distanceMap auf -1. Andernfalls kann nicht beurteilt werden, ob das Element zum Heap hinzugefügt wurde und ob es bestimmt wurde.

public static class NodeHeap {
    
    
        //Node类型的堆
        private Node[] nodes;
        //key对应的Node在堆中的位置是value
        private HashMap<Node, Integer> heapIndexMap;
        //key对应的Node当前距离源点最近距离
        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 this.size == 0;
        }

        public boolean isEntered(Node head) {
    
    
            return heapIndexMap.containsKey(head);
        }

        public boolean inHeap(Node head) {
    
    
            return isEntered(head) && heapIndexMap.get(head) != -1;
        }

        public 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 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;
            }
        }

        public void insertHeapify(Node node, int index) {
    
    
            while (distanceMap.get(nodes[index]) < distanceMap.get((index - 1) / 2)) {
    
    
                swap(distanceMap.get(nodes[index]), distanceMap.get((index - 1) / 2));
                index = (index - 1) / 2;
            }
        }

        public NodeRecord pop() {
    
    
            NodeRecord nodeRecord = new NodeRecord(nodes[0], distanceMap.get(0));
            swap(0, size - 1);
            heapIndexMap.put(nodes[size - 1], -1);
            distanceMap.remove(nodes[size - 1]);
            heapify(0, --size);
            return nodeRecord;
        }

        public void addOrUpdateOrIgnore(Node node, int distance) {
    
    
            if (inHeap(node)) {
    
    
                distanceMap.put(node, Math.min(distanceMap.get(node), distance));
                insertHeapify(node, distanceMap.get(node));
            }
            if (!isEntered(node)) {
    
    
                nodes[size] = node;
                heapIndexMap.put(node, size);
                distanceMap.put(node, distance);
                insertHeapify(node, size++);
            }
        }
    }

Die Hauptmethode
fügt den angegebenen Punkt logisch zum Heap hinzu, öffnet ihn, durchläuft alle Kanten und legt ihn im erweiterten Heap ab.

  public static HashMap<Node, Integer> dijkstra2(Node head, int size) {
    
    
        NodeHeap nh = new NodeHeap(size);
        nh.addOrUpdateOrIgnore(head, 0);
        HashMap<Node, Integer> result = new HashMap<>();

        while (!nh.isEmpty()) {
    
    
            NodeRecord record = nh.pop();
            Node cur = record.node;
            int distance = record.distance;

            for (Edge edge : cur.edges) {
    
    
                nh.addOrUpdateOrIgnore(edge.to, distance + edge.weight);
            }
            result.put(cur, distance);
        }
        return result;
    }

Supongo que te gusta

Origin blog.csdn.net/weixin_43936962/article/details/132263690
Recomendado
Clasificación