当前位置: 首页 > 知识库问答 >
问题:

Java上使用优先级队列的Dijkstra算法

闻人飞白
2023-03-14

我需要使用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;
    }
}

我需要填写最短路径方法并返回节点数组。但是,我不确定如何做到这一点。我知道我需要在某个时候进行优先排队,但有人可以向我解释一下如何吗?我已经制作了startNode,我知道我需要为它分配一个距离值0,其余节点的距离值为无穷大。另外,可比性从何而来?

共有2个答案

沃驰
2023-03-14

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

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

呼延化
2023-03-14

从<code>节点

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

边缘类:

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
}

有向图中的搜索方法:

@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;
}
 类似资料:
  • 我正在为Dikjstra算法做一个优先级队列。我目前在插入方法上有麻烦。我包含了整个类的代码,以防你需要更好地了解我想完成的事情。我将堆索引放在一个数组列表(heapIndex)中,堆放在另一个数组列表中。 那是我运行程序后的输出(值,优先级,堆索引)。*(-1)表示heapIndex中的空单元格。

  • 这是我写的Dijkstra算法的代码: 在这方面我不能理解的工作 这涉及到: < code>()运算符在这里有什么用?我是说它在这段代码中是如何运作的? 还有为什么我们使用

  • 在我实现Dijkstra算法的过程中,我有1个数组(包含所有节点)和1个优先级队列(包含所有节点)。每当一个节点排队时,我都会用新的距离和它来自哪里来更新所有相邻的节点,这样我就可以回溯路径。 优先级队列中的节点更新为新距离,数组中的节点更新为它来自的位置和新距离。当节点出列时,数组中的最终距离会更新: 用前一个节点的信息更新数组和用距离更新优先级队列是否可以接受? 只要找到更好的距离,就会发生这

  • 我正在使用优先级队列实现Dijkstra的算法,我想要一个函数从堆中删除一个元素,但我只能从Dijkstra的主节点索引中向它发送顶点索引,我找不到它在堆上的位置,我负担不起进行二进制搜索。有什么想法吗?

  • 我的问题是:每个节点的优先级是什么?我认为它是最小值的传入边缘的权重,但我不确定。这是真的吗? 第二个问题,当我提取队列的根时,如果这个节点不与任何一个被访问的节点邻接,它将如何工作?

  • 有人能帮我找到我的PQ的问题吗?