【问题标题】:Dijkstra's Algorithm using Priority Queue on JavaDijkstra 算法在 Java 上使用优先级队列
【发布时间】:2016-11-29 20:00:02
【问题描述】:

我需要使用 Java 中的优先级队列来实现 Dijkstra 算法。到目前为止,这是我的代码:

public class Node {
        long idNum;
        String label;
        HashSet<Edge> outEdges;
        HashSet<Edge> inEdges;
        int indegree;
        int outdegree; 

        int inNum, outNum;
        HashMap<Node, Edge> incoming, outgoing;

        Node(String label, Long idNum) {
            this.label = label;
            this.idNum = idNum;

            inNum =0;
            outNum=0; 
            incoming = new HashMap<Node, Edge>();
            outgoing = new HashMap<Node, Edge>();

        }
        Node(String Label){
            this.label=label;
        }

        public void addOutgoing(Node n, Edge e){
            if(n==null) return;
            outgoing.put(n,e);
            outNum++;
        }
        public void addIncoming(Node n, Edge e){
            if(n==null) return;
            incoming.put(n, e);
            inNum++;
        }
        public void delIn(Node n){
            incoming.remove(n);
            inNum--; 
        }
        public void delOut(Node n){
            outgoing.remove(n);
            outNum--;
        }

        public int getinNum(){
            return this.inNum; 
        }
        public boolean containsEdge(Edge e){
            if(incoming.containsValue(e) || outgoing.containsValue(e)){
                return true;
            }
            return false;
        }

        String getLabel(){
            return this.label;
        }


    }

    public class Edge {

        long idNum, weight;
        String sLabel, dLabel, eLabel;
        Node sNode, dNode;
        Node from;
        Node to;
        int distance;

        public Edge(long idNum, String sLabel, String dLabel, String eLabel) {
            this.idNum = idNum;
            // this.weight=weight;
            this.sLabel = sLabel;
            this.dLabel = dLabel;
            this.eLabel = eLabel;
        }

        public Edge(Node from, Node to) {
            this.from = from;
            this.to = to;
        }

        long getidNum() {
            return this.idNum;
        }

        public int getDistance() {
            return this.distance;
        }

    }


public class DiGraph implements DiGraph_Interface {
    // private Map<Node, Edge> digraph = new HashMap<Node, Edge>();
    private Map<String, Long> nodes = new HashMap<String, Long>();
    private Set<Node> nodes1 = new HashSet<Node>();
    private Set<Edge> edges = new HashSet<Edge>();
    private Map<Node, Node> edges1 = new HashMap<Node, Node>();
    private Set<Long> edge_ids = new HashSet<Long>();

    public long numEdges = 0;
    public long numNodes = 0;

    public DiGraph() { // default constructor
        // explicitly include this
        // we need to have the default constructor
        // if you then write others, this one will still be there

    }

    @Override
    public boolean addNode(long idNum, String label) {
        Node node = new Node(label, idNum);
        if(nodes.containsKey(label) || idNum <0 || label==null || nodes.containsValue(idNum)){
            return false;
        }
        nodes.put(label, idNum);
        nodes1.add(node);
        numNodes++;
        return true;

    }

    @Override
    public boolean addEdge(long idNum, String sLabel, String dLabel, long weight, String eLabel) {
        Edge e = new Edge(idNum, sLabel, dLabel, eLabel);
        Node n1 = new Node(sLabel, idNum);
        Node n2 = new Node(dLabel, idNum);
        if(edge_ids.contains(idNum)){
            return false;
        }
        for(Node n: nodes1){
            if(n.containsEdge(e)){
                return false;}
        }
        for(Edge edge: edges){
            if(edge.dLabel == dLabel && edge.sLabel == sLabel){return false;}
        }

        boolean check1=false;
        boolean check2=false;
        for(Node n: nodes1){
            if(n.label.equals(sLabel)){
                e.sNode=n; 
                check1=true;
            }
            if(n.label.equals(dLabel)){
                e.dNode=n;
                check2=true;
            }
        }
        if(!check1 || !check2){return false;}

        e.sNode.addOutgoing(e.dNode, e);
        e.dNode.addIncoming(e.sNode,e);

        n1.addOutgoing(n2, e);
        n2.addIncoming(n1, e);
        edge_ids.add(idNum);
        edges.add(e);
        numEdges++;
        return true; 

    }

    @Override
    public boolean delNode(String label) {
        Node node = new Node(label);
        if (!nodes.containsKey(label)) {
            return false;
        }
        if (nodes.containsKey(label) || nodes1.contains(node)) {
            nodes.remove(label, nodes.get(label));
            nodes1.remove(node);
            numNodes--;
            return true;
        }
        Set<Edge> remainingEdges = new HashSet<Edge>();
        for(Edge edge : edges){
            if(!node.containsEdge(edge)){
                remainingEdges.add(edge);
            }
        }   
        edges =  remainingEdges;
        numNodes--;
        return true;
    }

    @Override
    public boolean delEdge(String sLabel, String dLabel) {
        if(!nodes.containsKey(dLabel)|| !nodes.containsKey(sLabel)){
            return false;
        }
        for(Edge edge: edges){
            if(edge.dLabel == dLabel && edge.sLabel == sLabel){
                edge.sNode.delOut(edge.dNode);
                edge.dNode.delIn(edge.sNode);
                long idNum = edge.getidNum();
                numEdges--;
                edges.remove(edge);
                edge_ids.remove(idNum);
                return true;
            }
        }
        return false; 
    }


    @Override
    public long numNodes() {
        return this.numNodes;
    }

    @Override
    public long numEdges() {
        return this.numEdges;
    }

    @Override
    public String[] topoSort() {


        ArrayList<Node> nodeArray = new ArrayList<Node>();
        Stack<Node> nodeStack = new Stack<Node>();
        for(Node n: nodes1){
            nodeArray.add(n);
        }
        String[] topoSort = new String[(int) numNodes]; 
        int counter=0;

        int i=0;
        //for(int i=0; i< numNodes; i++){
            for(Node n: nodes1){

                if(n.inNum==0){
                    nodeStack.push(n);
                }
                if(nodeStack.isEmpty()){
                    return null;
                }
                while(!nodeStack.isEmpty()){
                    nodeStack.pop();
                    nodeArray.remove(n);
                if(n.incoming==null){
                    topoSort[i]=n.getLabel();
                    counter++;
                    i++;
                }
                }
            //}
        }
        if(counter != numNodes){
            return null;
        }
        return topoSort;
    }

    @Override
    public ShortestPathInfo[] shortestPath(String label) {
        Node startNode = new Node(label);

        return null;
    }
}

我需要填写 shortestPath 方法并返回一个节点数组。但是,我不确定如何去做。我知道我需要在某个时候设置优先级队列,但是有人可以向我解释一下如何吗?我已经创建了 startNode,我知道我需要为它分配一个距离值 0,而其余节点的距离值是无穷大。还有什么可比的?

【问题讨论】:

    标签: java priority-queue dijkstra


    【解决方案1】:

    从你的 Node 类开始:

    public class Node {
        // add a parent attribute to the class
        // this will be used in your shortestPath method
        // i have explained it below
        private Node parent;
    }
    

    Edge 类:

    public class Edge {
        // why do you have four of these? You only need two
        private Node sNode, dNode;
        private Node from;
        private Node to;
    }
    

    我的有向图类看起来太复杂了。你可以稍微简化一下:

    public class DiGraph implements DiGraph_Interface {
    
        private LinkedList<Node>[] adjList;
        private HashSet<Edge> edges;
    
        // implement the interface methods as you have done
    }
    

    DiGraph中的搜索方式:

    @Override
    public ShortestPathInfo[] shortestPath(String label) {
        PriorityQueue<Node> queue = new PriorityQueue<>(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Node n1 = (Node) o1;
                Node n2 = (Node) o2;
                // this assumes that lower number is higher priority
                // also, this compare method compares the two string values
                // from the two nodes. If n1.label is lexicographically smaller
                // then n1 will be added high up in the queue
                // you can compare based on the node's idNum too
                // you should implement it based on your requirements
                return n1.label.compareTo(n2.label);
            }
        });
    
        // create a method getScrNode()
        // in that method, traverse the linkedList to find the srcNode
        // You can do this easily if you keep Map of nodes, like you did in your code
        // but that just takes too much memory
        Node start = getSrcNode(label);
        queue.add(start);
        while (!queue.isEmpty()) {
            /*This is your main exercise. You should solve it yourself.
            Somewhere here you should set the parent of a node
            */            
        }
    
        // print the path
        if (done) {
            while (current.getParent() != null)
                System.out.println(current.getLabel());
        }
        return null;
    }
    

    【讨论】:

      【解决方案2】:

      您可以使用 java.util.TreeSet 作为优先级队列。它包含用于将元素放入队列的方法 add() 和用于获取具有最低值的元素的 pollFirst() 方法。

      为了比较,您可以将要放入队列的类对象(很可能不仅仅是 Node,而是一个包含对 Node 的引用和恢复route) 实现接口 Comparable 或创建 Comparator 并将其作为参数传递给 TreeSet 构造函数。在任何一种情况下,您都需要实现方法 compareTo(),该方法将根据算法的要求比较节点的距离。

      【讨论】:

        猜你喜欢
        • 2013-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多