Dijkstra 算法用優先隊列的java實現

dijkstra這個算法的意思百度下大概就能明白。我主要講的是如何實現。
首先,我們如何用java去保存一張有向圖?
我用hashmap去存它的起點位置,然後value用list加節點的方式,感覺就像鏈表一樣。去存儲
地圖模板

//創建地圖
/*
 * S——16——>C—— 2——>D
 * | \     ^ ^     ^
 * 4  8    |  \    |
 * |    \  7   5   6
 * v     v |    \  |
 * A—— 3——>B—— 1——>E
 */
class Graph
{
    Map<Character,List<Node>> map=new HashMap<Character,List<Node>>();//輸出的地圖
    Graph()
    {
        List<Node> list=new ArrayList<Node>();
        list.add(new Node('S','A',4));
        list.add(new Node('S','B',8));
        list.add(new Node('S','C',16));
        list.add(new Node('A','B',3));
        list.add(new Node('B','C',7));
        list.add(new Node('B','E',1));
        list.add(new Node('C','D',2));
        list.add(new Node('E','C',5));
        list.add(new Node('E','D',6));

        for(int i=0;i<list.size();i++)
        {
            List<Node> temp=map.get(list.get(i).getSrc());
            if(temp==null)
                temp=new ArrayList<Node>();
            temp.add(list.get(i));
            map.put(list.get(i).getSrc(), temp);
        }
    }
}

class Node
{
    private Character src;//起點
    private Character des;//終點
    private int len;      //距離長度
    private int path=Integer.MAX_VALUE;//初始設置爲無窮長
    boolean die=false;    //訪問過一次後就死亡
    Node(){}
    Node(Character src,Character des,int len)
    {
        this.src=src;
        this.des=des;
        this.len=len;
    }
    void setPath(int path)
    {
        this.path=path;
    }
    int getPath()
    {
        return path;
    }
    Character getSrc()
    {
        return src;
    }
    Character getDes()
    {
        return des;
    }
    int getLen()
    {
        return len;
    }
}

然後爲了凸顯出鏈表的效率。我們先來個普通模式的dijkstra算法的實現,這個方式去實現其算法複雜度是O(V^2)V是節點數量

public class Dijkstra 
{  
    public static Map<Character,Integer> dijkstra(Map<Character,List<Node>> map,Character c)
    {
        Queue<Node> heap=new LinkedList<Node>();

        //初始節點
        Node root=new Node(c,c,0);
        root.setPath(0);
        heap.add(root);

        Map<Character,Integer> result=new HashMap<Character,Integer>();
        while(!heap.isEmpty())
        {
            Node x=heap.poll(),y = null;
            List<Node> temp=map.get(x.getDes());
            if(temp==null)
                continue;
            for(int i=0;i<temp.size();i++)
            {
                y=temp.get(i);
                if(y.getPath()>x.getPath()+y.getLen())
                {
                    temp.get(i).setPath(x.getPath()+y.getLen());
                    if(temp.get(i).die==false)
                    {
                        heap.add(temp.get(i)); 
                        temp.get(i).die=true;
                    }
                    if(result.get(temp.get(i).getDes())==null)
                    {
                        result.put(temp.get(i).getDes(),temp.get(i).getPath());
                    }
                    if(result.get(temp.get(i).getDes())>temp.get(i).getPath())
                    {
                        result.put(temp.get(i).getDes(),temp.get(i).getPath());
                    }
                }
            }
        }
        return result;
    }

    public static void main(String[] argc)
    {
        Graph graph=new Graph();
        Map<Character,Integer> result=dijkstra(graph.map,'S');
        for(Map.Entry<Character,Integer> entry:result.entrySet())
        {
            System.out.println("S-->"+entry.getKey()+" 長度"+entry.getValue());
        }
    }
}

這裏寫圖片描述

大致就是這樣實現下。
然後我們就要討論爲什麼要用有限隊列?因爲它是堆的形式。堆便於取出最值,如果一個算法中需要多次取最大或者最小值,那麼堆就是個最好的存放容器,其建堆只要O(N)的時間,增刪,堆化時間複雜度也只要O(logn)。有很大的優勢。

用堆去存儲 複雜度降低到O(VlogV)
代碼如下

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.PriorityQueue;

//創建地圖
/*
 * S——16——>C—— 2——>D
 * | \     ^ ^     ^
 * 4  8    |  \    |
 * |    \  7   5   6
 * v     v |    \  |
 * A—— 3——>B—— 1——>E
 */
class Graph
{
    Map<Character,List<Node>> map=new HashMap<Character,List<Node>>();//輸出的地圖
    Graph()
    {
        List<Node> list=new ArrayList<Node>();
        list.add(new Node('S','A',4));
        list.add(new Node('S','B',8));
        list.add(new Node('S','C',16));
        list.add(new Node('A','B',3));
        list.add(new Node('B','C',7));
        list.add(new Node('B','E',1));
        list.add(new Node('C','D',2));
        list.add(new Node('E','C',5));
        list.add(new Node('E','D',6));

        for(int i=0;i<list.size();i++)
        {
            List<Node> temp=map.get(list.get(i).getSrc());
            if(temp==null)
                temp=new ArrayList<Node>();
            temp.add(list.get(i));
            map.put(list.get(i).getSrc(), temp);
        }
    }
}

class Node
{
    private Character src;//起點
    private Character des;//終點
    private int len;      //距離長度
    Node(){}
    Node(Character src,Character des,int len)
    {
        this.src=src;
        this.des=des;
        this.len=len;
    }
    Character getSrc()
    {
        return src;
    }
    Character getDes()
    {
        return des;
    }
    int getLen()
    {
        return len;
    }
}
public class Dijkstra2 
{
    static Map<Character, Integer> dijkstra(Map<Character,List<Node>> graph,Character source)
    {
        //堆的初始化
        PriorityQueue<Map.Entry<Character, Integer>> queue=new PriorityQueue<Map.Entry<Character, Integer>>((a,b)->a.getValue()-b.getValue());
        Map<Character, Integer> map=new HashMap<Character, Integer>();
        map.put(source, 0);
        queue.add(map.entrySet().iterator().next());

        Map<Character, Integer> visited=new HashMap<Character, Integer>();
        while(!queue.isEmpty())
        {
            //從堆中獲取最小距離的節點
            Entry<Character, Integer> temp=queue.poll();
            //講距離值添加到visited
            if(visited.get(temp.getKey())==null)
                visited.put(temp.getKey(), temp.getValue());
            if(graph.get(temp.getKey())==null)
            {
                continue;
            }
            //更新與temp相鄰各節點neighbourdistance
            for(int i=0; i<graph.get(temp.getKey()).size();i++)
            {
                if(visited.get(graph.get(temp.getKey()).get(i).getDes())!=null)
                {
                    continue;
                }

                Map<Character, Integer> temp2=new HashMap<Character, Integer>();
                temp2.put(graph.get(temp.getKey()).get(i).getDes(), temp.getValue()+graph.get(temp.getKey()).get(i).getLen());
                queue.add(temp2.entrySet().iterator().next());
            }
        }
        return visited;
    }
    public static void main(String[] argc)
    {
        Graph graph=new Graph();
        Map<Character, Integer> result=dijkstra(graph.map,'S');
        for(Map.Entry<Character,Integer> entry:result.entrySet())
        {
            System.out.println("S-->"+entry.getKey()+" 長度"+entry.getValue());
        }
    }
}

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章