首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Dijksta算法-邻接表和最小堆- java

Dijksta算法-邻接表和最小堆- java
EN

Stack Overflow用户
提问于 2018-10-07 06:42:08
回答 1查看 777关注 0票数 0

我已经使用这段代码实现了无向图,并找到了从节点0到节点5的最短路径。

源顶点:0到顶点5距离: 10

但是,我正在寻找打印最短路径,这应该看起来像:

0-4- 5。

有什么建议请提出来。完成的代码如下:

代码语言:javascript
复制
    import java.util.LinkedList;

public class DijkstraUsingMinHeap {
    static class Edge {
        int source;
        int destination;
        int weight;

        public Edge(int source, int destination, int weight) {
            this.source = source;
            this.destination = destination;
            this.weight = weight;
        }
    }

    static class HeapNode{
        int vertex;
        int distance;
    }
    static class Graph {
        int vertices;
        LinkedList<Edge>[] adjacencylist;

        Graph(int vertices) {
            this.vertices = vertices;
            adjacencylist = new LinkedList[vertices];
            //initialize adjacency lists for all the vertices
            for (int i = 0; i <vertices ; i++) {
                adjacencylist[i] = new LinkedList<>();
            }
        }

        public void addEdge(int source, int destination, int weight) {
            Edge edge = new Edge(source, destination, weight);
            adjacencylist[source].addFirst(edge);

            edge = new Edge(destination, source, weight);
            adjacencylist[destination].addFirst(edge); //for undirected graph
        }

        public void dijkstra_GetMinDistances(int sourceVertex){
            int INFINITY = Integer.MAX_VALUE;
            boolean[] SPT = new boolean[vertices];

//          //create heapNode for all the vertices
            HeapNode [] heapNodes = new HeapNode[vertices];
            for (int i = 0; i <vertices ; i++) {
                heapNodes[i] = new HeapNode();
                heapNodes[i].vertex = i;
                heapNodes[i].distance = INFINITY;
            }

            //decrease the distance for the first index
            heapNodes[sourceVertex].distance = 0;

            //add all the vertices to the MinHeap
            MinHeap minHeap = new MinHeap(vertices);
            for (int i = 0; i <vertices ; i++) {
                minHeap.insert(heapNodes[i]);
            }
            //while minHeap is not empty
            while(!minHeap.isEmpty()){
                //extract the min
                HeapNode extractedNode = minHeap.extractMin();

                //extracted vertex
                int extractedVertex = extractedNode.vertex;
                SPT[extractedVertex] = true;

                //iterate through all the adjacent vertices
                LinkedList<Edge> list = adjacencylist[extractedVertex];
                for (int i = 0; i <list.size() ; i++) {
                    Edge edge = list.get(i);
                    int destination = edge.destination;
                    //only if  destination vertex is not present in SPT
                    if(SPT[destination]==false ) {
                        ///check if distance needs an update or not
                        //means check total weight from source to vertex_V is less than
                        //the current distance value, if yes then update the distance
                        int newKey =  heapNodes[extractedVertex].distance + edge.weight ;
                        int currentKey = heapNodes[destination].distance;
                        if(currentKey>newKey){
                            decreaseKey(minHeap, newKey, destination);
                            heapNodes[destination].distance = newKey;
                        }
                    }
                }
            }
            //print SPT
            printDijkstra(heapNodes, sourceVertex);
        }

        public void decreaseKey(MinHeap minHeap, int newKey, int vertex){

            //get the index which distance's needs a decrease;
            int index = minHeap.indexes[vertex];

            //get the node and update its value
            HeapNode node = minHeap.mH[index];
            node.distance = newKey;
            minHeap.bubbleUp(index);
        }

        public void printDijkstra(HeapNode[] resultSet, int sourceVertex){
            for (int i = 0; i <vertices ; i++) {
                if ( i == 5 ) {
                System.out.println("Source Vertex: " + sourceVertex + " to vertex " +   + i +
                        " distance: " + resultSet[i].distance);}
            }
        }
    }
    static class MinHeap{
        int capacity;
        int currentSize;
        HeapNode[] mH;
        int [] indexes; //will be used to decrease the distance


        public MinHeap(int capacity) {
            this.capacity = capacity;
            mH = new HeapNode[capacity + 1];
            indexes = new int[capacity];
            mH[0] = new HeapNode();
            mH[0].distance = Integer.MIN_VALUE;
            mH[0].vertex=-1;
            currentSize = 0;
        }


        public void insert(HeapNode x) {
            currentSize++;
            int idx = currentSize;
            mH[idx] = x;
            indexes[x.vertex] = idx;
            bubbleUp(idx);
        }

        public void bubbleUp(int pos) {
            int parentIdx = pos/2;
            int currentIdx = pos;
            while (currentIdx > 0 && mH[parentIdx].distance > mH[currentIdx].distance) {
                HeapNode currentNode = mH[currentIdx];
                HeapNode parentNode = mH[parentIdx];

                //swap the positions
                indexes[currentNode.vertex] = parentIdx;
                indexes[parentNode.vertex] = currentIdx;
                swap(currentIdx,parentIdx);
                currentIdx = parentIdx;
                parentIdx = parentIdx/2;
            }
        }

        public HeapNode extractMin() {
            HeapNode min = mH[1];
            HeapNode lastNode = mH[currentSize];
//            update the indexes[] and move the last node to the top
            indexes[lastNode.vertex] = 1;
            mH[1] = lastNode;
            mH[currentSize] = null;
            sinkDown(1);
            currentSize--;
            return min;
        }

        public void sinkDown(int k) {
            int smallest = k;
            int leftChildIdx = 2 * k;
            int rightChildIdx = 2 * k+1;
            if (leftChildIdx < heapSize() && mH[smallest].distance > mH[leftChildIdx].distance) {
                smallest = leftChildIdx;
            }
            if (rightChildIdx < heapSize() && mH[smallest].distance > mH[rightChildIdx].distance) {
                smallest = rightChildIdx;
            }
            if (smallest != k) {

                HeapNode smallestNode = mH[smallest];
                HeapNode kNode = mH[k];

                //swap the positions
                indexes[smallestNode.vertex] = k;
                indexes[kNode.vertex] = smallest;
                swap(k, smallest);
                sinkDown(smallest);
            }
        }

        public void swap(int a, int b) {
            HeapNode temp = mH[a];
            mH[a] = mH[b];
            mH[b] = temp;
        }

        public boolean isEmpty() {
            return currentSize == 0;
        }

        public int heapSize(){
            return currentSize;
        }
    }
     public static void main(String[] args) {
            int vertices = 6;
            Graph graph = new Graph(vertices);
            int sourceVertex = 0;

            graph.addEdge(0, 1, 4);
            graph.addEdge(0, 2, 3);
            graph.addEdge(1, 3, 2);
            graph.addEdge(1, 2, 5);
            graph.addEdge(2, 3, 7);
            graph.addEdge(3, 4, 2);
            graph.addEdge(4, 0, 4);
            graph.addEdge(4, 1, 4);
            graph.addEdge(4, 5, 6);
            graph.dijkstra_GetMinDistances(sourceVertex);
    }
}

提前感谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-10-07 08:37:10

更新:更改为命名节点和边,并列出边。

看起来有很多这样的代码。下面是一个替代的Java 8+实现。

Dijkstra's algorithm完全在startAt方法中实现。

代码语言:javascript
复制
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public  final class Graph {
    private static final class Edge {
        final String name;
        final int weight;
        Edge(String name, int weight) {
            this.name = name;
            this.weight = weight;
        }
        @Override
        public String toString() {
            return this.name + ":" + this.weight;
        }
    }
    private static final class Node {
        final String name;
        Map<Node, Edge> edges = new HashMap<>();
        Node[] path;
        int pathWeight;
        Node(String name) {
            this.name = name;
        }
    }

    private Map<String, Node> nodes = new HashMap<>();

    public void addEdge(String sourceName, String destinationName, int weight, String edgeName) {
        Node source = this.nodes.computeIfAbsent(sourceName, Node::new);
        Node dest = this.nodes.computeIfAbsent(destinationName, Node::new);
        Edge edge = new Edge(edgeName, weight);
        source.edges.put(dest, edge);
        dest.edges.put(source, edge);
    }

    public void startAt(String startNodeName) {
        this.nodes.values().forEach(n -> n.path = null);
        Node source = this.nodes.computeIfAbsent(startNodeName, Node::new);
        source.path = new Node[] { source };
        source.pathWeight = 0;
        TreeSet<Node> pending = new TreeSet<>((a, b) -> Integer.compare(a.pathWeight, b.pathWeight));
        pending.add(source);
        while ((source = pending.pollFirst()) != null) {
            for (Entry<Node, Edge> edge : source.edges.entrySet()) {
                Node dest = edge.getKey();
                int weight = source.pathWeight + edge.getValue().weight;
                if (dest.path == null || weight < dest.pathWeight
                                      || (weight == dest.pathWeight && source.path.length + 1 < dest.path.length)) {
                    if (dest.path != null)
                        pending.remove(dest);
                    dest.path = Arrays.copyOf(source.path, source.path.length + 1);
                    dest.path[source.path.length] = dest;
                    dest.pathWeight = weight;
                    pending.add(dest);
                }
            }
        }
    }

    public String getPath(String endNodeName) {
        Node node = this.nodes.get(endNodeName);
        if (node == null || node.path == null)
            return "Unreachable";
        String path = Arrays.stream(node.path).map(n -> n.name).collect(Collectors.joining(" - "));
        String pathEdges = IntStream.range(1, node.path.length)
                .mapToObj(i -> node.path[i - 1].edges.get(node.path[i]).toString())
                .collect(Collectors.joining(" + "));
        return path + " (distance: " + node.pathWeight + " = " + pathEdges + ")";
    }
}

测试1(原始边)

代码语言:javascript
复制
Graph graph = new Graph();
graph.addEdge("0", "1", 4, "A");
graph.addEdge("0", "2", 3, "B");
graph.addEdge("1", "2", 1, "C");
graph.addEdge("1", "3", 2, "D");
graph.addEdge("2", "3", 4, "E");
graph.addEdge("3", "4", 2, "F");
graph.addEdge("4", "5", 6, "G");
graph.startAt("0");
System.out.println(graph.getPath("5"));

输出1

代码语言:javascript
复制
0 - 1 - 3 - 4 - 5 (distance: 14 = A:4 + D:2 + F:2 + G:6)

测试2(更新的边缘)

代码语言:javascript
复制
Graph graph = new Graph();
graph.addEdge("0", "1", 4, "A");
graph.addEdge("0", "2", 3, "B");
graph.addEdge("1", "3", 2, "C");
graph.addEdge("1", "2", 5, "D");
graph.addEdge("2", "3", 7, "E");
graph.addEdge("3", "4", 2, "F");
graph.addEdge("4", "0", 4, "G");
graph.addEdge("4", "1", 4, "H");
graph.addEdge("4", "5", 6, "I");
graph.startAt("0");
System.out.println(graph.getPath("5"));

输出2

代码语言:javascript
复制
0 - 4 - 5 (distance: 10 = G:4 + I:6)

有关两个测试的演示,请参阅IDEONE

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52683954

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档