转载自:http://www.2cto.com/kf/201304/200733.html

 

     看得略有点久,所以加了注释上去

package test;

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


//首先,我们需要先定义一个边界值的类Edge
//接着,我们需要定义一个顶点的类
//然后,我们根据顶点去遍历边界值,每次更新
//当所有的顶点都包括进去后,那自然也就得到最短路径了
public class Dijkstra {

    public static Map<String, Vertex> vertexMap = new HashMap<String, Vertex>();

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Vertex v1 = new Vertex("v1");
        Vertex v2 = new Vertex("v2");
        Vertex v3 = new Vertex("v3");
        Vertex v4 = new Vertex("v4");
        Vertex v5 = new Vertex("v5");

        List<Edge> e1l = v1.adj;
        List<Edge> e2l = v2.adj;
        List<Edge> e3l = v3.adj;
        List<Edge> e4l = v4.adj;
        // 因为V5这个点并没有到其它任何一点,所以不加入
        // List<Edge> e5l = v5.adj;

        Edge e12 = new Edge(v2, 10);
        Edge e14 = new Edge(v4, 30);
        Edge e15 = new Edge(v5, 100);
        e1l.add(e14);
        e1l.add(e15);
        e1l.add(e12);

        Edge e23 = new Edge(v3, 50);
        e2l.add(e23);

        Edge e35 = new Edge(v5, 10);
        e3l.add(e35);

        Edge e43 = new Edge(v3, 20);
        Edge e45 = new Edge(v5, 60);
        e4l.add(e43);
        e4l.add(e45);

        /*
         * 以上代码构建有向图 v1---->v5:100 v1----->V4:30 v1------>V2:10
         * 
         * V2------>V3:50 V3------->V5:10 v4------->V3:20 v4------->V5:60
         */
        vertexMap.put("v1", v1);
        vertexMap.put("v2", v2);
        vertexMap.put("v3", v3);
        vertexMap.put("v4", v4);
        vertexMap.put("v5", v5);

        dijkstral("v1", "v5");
    }

    // 每一次迭代,会以整个点来更新图,如果更新,就把点加进去
    // 问题在于找的那个点,是否有什么不对
    // c代表整个的路径长度
    public static void dijkstral(final String startName, final String endName) {
        //该队列以权值升序排列,因为Vertex实现Comparable接口
        PriorityQueue<Vertex> queue = new PriorityQueue<Vertex>();
        Vertex start = vertexMap.get(startName);
        start.dist = 0;
        for (Vertex v : vertexMap.values())
            queue.add(v);

        int seenNum = 0;
        while (!queue.isEmpty() && seenNum < vertexMap.size()) {
            Vertex v = queue.remove();
            if (v.name.equals(endName)) { // 恰好是自己要找的那个点
                System.out.println(startName + "---->" + v.name + "距离是:     "
                        + v.dist);
                System.out.println(getPreNames(v));
                break;
            }
            // 如果这个顶点有被访问过,那么我们跳过这一次的执行
            if (v.visited)
                continue;
            v.visited = true;// 已经被访问过了,所以设置为true
            seenNum++;
            // 每次遍历,如果找到还有更小的点,那么就把路径更新上去
            for (Edge e : v.adj) {
                Vertex w = e.dest;
                double v_to_w = e.cost;
                if (w.dist > v.dist + v_to_w) {
                    w.dist = v.dist + v_to_w;
                    w.prev = v;
                    queue.remove(w);
                    queue.add(w);
                }
            }
        }
    }

    // dest代表着到哪个点
    // cost代表着到那个点的距离
    static class Edge {
        public Vertex dest;
        public double cost;

        public Edge(Vertex d, double c) {
            this.dest = d;
            this.cost = c;
        }
    }

    // name:顶点的名字
    // adj:分别到哪些个点的list
    // dist:最短的距离
    // prev:表示哪个点到它这
    // visited:是否有被访问过
    static class Vertex implements Comparable<Vertex>{
        public String name;
        public List<Edge> adj;
        public double dist;
        public Vertex prev;
        public boolean visited;

        public Vertex(String nm) {
            this.name = nm;
            adj = new ArrayList<Edge>();
            reset();
        }

        public void reset() {
            visited = false;
            dist = 99999;
        }

        @Override
        public int compareTo(Vertex o) {
            // TODO Auto-generated method stub
            double c = o.dist;
            return dist < c ? -1:dist > c ? 1:0;
        }
    }

    // 得到最短路径的路线,并整理好吰,返回
    public static String getPreNames(Vertex v) {
        String routeEndName = v.name;
        StringBuilder sb = new StringBuilder();
        // 先从终点起,把所有的点都弄出来
        while (v.prev != null) {
            sb.append(v.prev.name + ",");
            v = v.prev;
        }
        String reverseRoute = routeEndName + "," + sb.toString();
        String[] reverseArray = reverseRoute.split(",");
        StringBuilder route = new StringBuilder();
        // 再调整顺序,返回
        for (int i = 0; i < reverseArray.length; i++) {
            route.append(reverseArray[reverseArray.length - 1 - i]);
            route.append(",");
        }
        return route.substring(0, route.length() - 1);
    }
}