美文网首页
最短路径

最短路径

作者: Phoebe_Liu | 来源:发表于2018-12-05 18:04 被阅读0次

参考实现: https://blog.csdn.net/qq_39630587/article/details/79030812

最短路径:如果从图中某一顶点(源点)到达另一顶点(终点)的路径可能不止一条,如何找到一条路径使得沿此路径上各边的权值总和(称为路径长度)达到最小。
Drjkstra 与 prim区别:

  1. Prim是计算最小生成树的算法,比如为N个村庄修路,怎么修花销最少。
    Dijkstra是计算最短路径的算法,比如从a村庄走到其他任意村庄的距离。

  2. Prim算法中有一个统计总len的变量,每次都要把到下一点的距离加到len中;
    Dijkstra算法中却没有,只需要把到下一点的距离加到cls数组中即可;

  3. Prim算法的更新操作更新的cls是已访问集合到未访问集合中各点的距离;
    for (j=0;j<n;j++)
    {
    if (!visited[j] && map[j][nid]<adjset[j])//更新条件:j点未访问,加入新点后已访问集合到j的距离变小了
    {
    adjset[j] = map[j][nid];
    }
    }

Dijkstra算法的更新操作更新的cls是源点到未访问集合中各点的距离,已经访问过的相当于已经找到源点到它的最短距离了;
for (j=1;j<=n;j++)
{
if(!vis[j]&&map[nxt][j]<MAX&&(min+map[nxt][j])<cls[j])//更新条件:j点未访问,新点与j点之间有路,
cls[j]=cls[nxt]+map[nxt][j];
}


Dijkstra 狄克斯特拉

  • 贪心算法
  • 将节点维护为两个集合: S集合(已经求出最短路径的节点),V-S集合(尚未求出最短路径的节点)
  • 维护三个计算队列:
    • 源节点s0到各个节点的最短距离
    • 每个节点是否被访问过
    • 使得s0到各节点距离最近的跳板节点
public class GraphByMatrix {
    public static final boolean UNDIRECTED_GRAPH = false;//无向图标志
    public static final boolean DIRECTED_GRAPH = true;//有向图标志
 
    public static final boolean ADJACENCY_MATRIX = true;//邻接矩阵实现
    public static final boolean ADJACENCY_LIST = false;//邻接表实现
 
    public static final int MAX_VALUE = Integer.MAX_VALUE;
    private boolean graphType;
    private boolean method;
    private int vertexSize;
    private int matrixMaxVertex;
 
    //存储所有顶点信息的一维数组
    private Object[] vertexesArray;
    //存储图中顶点之间关联关系的二维数组,及边的关系
    private int[][] edgesMatrix;
 
    // 记录第i个节点是否被访问过
    private boolean[] visited;
 
    /**
     * @param graphType 图的类型:有向图/无向图
     * @param method    图的实现方式:邻接矩阵/邻接表
     */
    public GraphByMatrix(boolean graphType, boolean method, int size) {
        this.graphType = graphType;
        this.method = method;
        this.vertexSize = 0;
        this.matrixMaxVertex = size;
 
        if (this.method) {
            visited = new boolean[matrixMaxVertex];
            vertexesArray = new Object[matrixMaxVertex];
            edgesMatrix = new int[matrixMaxVertex][matrixMaxVertex];
 
            //对数组进行初始化,顶点间没有边关联的值为Integer类型的最大值
            for (int row = 0; row < edgesMatrix.length; row++) {
                for (int column = 0; column < edgesMatrix.length; column++) {
                    edgesMatrix[row][column] = MAX_VALUE;
                }
            }
 
        }
    }
 
    /********************最短路径****************************/
    //计算一个顶点到其它一个顶点的最短距离
    public void Dijkstra(Object obj) throws Exception {
        Dijkstra(getVertexIndex(obj));
    }
    public void Dijkstra(int v0) {
        int[] dist = new int[matrixMaxVertex];
        int[] prev = new int[matrixMaxVertex];
 
        //初始化visited、dist和path
        for (int i = 0; i < vertexSize; i++) {
            //一开始假定取直达路径最短
            dist[i] = edgesMatrix[v0][i];
            visited[i] = false;
 
            //直达情况下的最后经由点就是出发点
            if (i != v0 && dist[i] < MAX_VALUE)
                prev[i] = v0;
            else
                prev[i] = -1; //无直达路径
        }
 
        //初始时源点v0∈visited集,表示v0 到v0的最短路径已经找到
        visited[v0] = true;
 
        // 下来假设经由一个点中转到达其余各点,会近些,验证之
        // 再假设经由两个点中转,会更近些,验证之,.....
        // 直到穷举完所有可能的中转点
        int minDist;
        int v = 0;
        for (int i = 1; i < vertexSize; i++) {
            //挑一个距离最近经由点,下标装入 v
            minDist = MAX_VALUE;
 
            for (int j = 0; j < vertexSize; j++) {
                if ((!visited[j]) && dist[j] < minDist) {
                    v = j;                             // 经由顶点j中转则距离更短
                    minDist = dist[j];
                }
            }
            visited[v] = true;
 
            /*顶点v并入S,由v0到达v顶点的最短路径为min.
              假定由v0到v,再由v直达其余各点,更新当前最后一个经由点及距离*/
            for (int j = 0; j < vertexSize; j++) {
                if ((!visited[j]) && edgesMatrix[v][j] < MAX_VALUE) {
 
                    if (minDist + edgesMatrix[v][j] <= dist[j]) {
                        //如果多经由一个v点到达j点的 最短路径反而要短,就更新
                        dist[j] = minDist + edgesMatrix[v][j];
 
                        prev[j] = v;                    //经由点的序号
                    }
 
                }
            }
 
        }
 
        for (int i = 1; i < matrixMaxVertex; i++) {
            System.out.println("**" + vertexesArray[v0] + "-->" +vertexesArray[i] + " 的最短路径是:" + dist[i]);
        }
    }
 
    //获取顶点值在数组里对应的索引
    private int getVertexIndex(Object obj) throws Exception {
        int index = -1;
        for (int i = 0; i < vertexSize; i++) {
            if (vertexesArray[i].equals(obj)) {
                index = i;
                break;
            }
        }
        if (index == -1) {
            throw new Exception("没有这个值!");
        }
 
        return index;
    }
 
    /**
     * 单源最短路径算法,用于计算一个节点到其他!!所有节点!!的最短路径
     */
    public void Dijkstra2(int v0) {
        // LinkedList实现了Queue接口 FIFO
        Queue<Integer> queue = new LinkedList<Integer>();
        for (int i = 0; i < vertexSize; i++) {
            visited[i] = false;
        }
 
        //这个循环是为了确保每个顶点都被遍历到
        for (int i = 0; i < vertexSize; i++) {
            if (!visited[i]) {
                queue.add(i);
                visited[i] = true;
 
                while (!queue.isEmpty()) {
                    int row = queue.remove();
                    System.out.print(vertexesArray[row] + "-->");
 
                    for (int k = getMin(row); k >= 0; k = getMin(row)) {
                        if (!visited[k]) {
                            queue.add(k);
                            visited[k] = true;
                        }
                    }
 
                }
            }
        }
    }
 
    private int getMin( int row) {
        int minDist = MAX_VALUE;
        int index = 0;
        for (int j = 0; j < vertexSize; j++) {
            if ((!visited[j]) && edgesMatrix[row][j] < minDist) {
                minDist = edgesMatrix[row][j];
                index = j;
            }
        }
        if (index == 0) {
            return -1;
        }
        return index;
    }
 
    public boolean addVertex(Object val) {
        assert (val != null);
        vertexesArray[vertexSize] = val;
        vertexSize++;
        return true;
    }
 
    public boolean addEdge(int vnum1, int vnum2, int weight) {
        assert (vnum1 >= 0 && vnum2 >= 0 && vnum1 != vnum2 && weight >= 0);
 
        //有向图
        if (graphType) {
            edgesMatrix[vnum1][vnum2] = weight;
 
        } else {
            edgesMatrix[vnum1][vnum2] = weight;
            edgesMatrix[vnum2][vnum1] = weight;
        }
 
        return true;
    }
 
public void testWeight() throws Exception {
        GraphByMatrix graph = new GraphByMatrix(Graph.UNDIRECTED_GRAPH, Graph.ADJACENCY_MATRIX, 6);
 
        graph.addVertex("1");
        graph.addVertex("2");
        graph.addVertex("3");
        graph.addVertex("4");
        graph.addVertex("5");
        graph.addVertex("6");
 
        graph.addEdge(0, 1,7);
        graph.addEdge(0, 2,9);
        graph.addEdge(0, 5,14);
 
        graph.addEdge(1, 3,15);
        graph.addEdge(1, 2,10);
 
        graph.addEdge(2, 3,11);
        graph.addEdge(2, 5,2);
 
        graph.addEdge(3, 4,6);
        graph.addEdge(4, 5,9);
 
        graph.Dijkstra(0);
        System.out.println();
        graph.Dijkstra("1");
        System.out.println();
        graph.Dijkstra2(0);
        System.out.println();
    }

}

第二种写法:

package com.android.test.demo.graph;

import android.util.ArrayMap;
import android.util.Log;

import com.google.common.graph.ElementOrder;
import com.google.common.graph.MutableValueGraph;
import com.google.common.graph.ValueGraphBuilder;

import java.util.Map;
import java.util.Set;

/**
 * Created by tech on 18-1-11.
 */

public class Dijkstra {
    private final static String TAG = "Dijkstra";

    private static final String V0 = "v0";
    private static final String V1 = "v1";
    private static final String V2 = "v2";
    private static final String V3 = "v3";
    private static final String V4 = "v4";
    private static final String V5 = "v5";

    private static final String A = "A";
    private static final String B = "B";
    private static final String C = "C";
    private static final String D = "D";
    private static final String E = "E";



    public static void test() {
        MutableValueGraph<String, Integer> graph = buildGraph1();
        Log.i(TAG, "graph: " + graph);

        testDijkstra(graph, V0);


        MutableValueGraph<String, Integer> graph2 = buildGraph2();
        Log.i(TAG, "graph: " + graph2);

        testDijkstra(graph2, A);
    }

    private static void testDijkstra(MutableValueGraph<String, Integer> graph, String startNode) {
        Set<String> nodes = graph.nodes();
        Map<String, NodeExtra> nodeExtras = new ArrayMap<>(nodes.size());
        /**
         * 初始化extra
         */
        for (String node : nodes) {
            NodeExtra extra = new NodeExtra();
            extra.nodeName = node;
            /*初始最短路径:存在边时,为边的权值;没有边时为无穷大*/
            final int value = graph.edgeValueOrDefault(startNode, node, Integer.MAX_VALUE);
            extra.distance = value;
            extra.visited = false;
            if (value < Integer.MAX_VALUE) {
                extra.path = startNode + " -> " + node;
                extra.preNode = startNode;
            }
            nodeExtras.put(node, extra);
        }

        /**
         * 一开始可设置开始节点的最短路径为0
         */
        NodeExtra current = nodeExtras.get(startNode);
        current.distance = 0;
        current.visited = true;
        current.path = startNode;
        current.preNode = startNode;
        /*需要循环节点数遍*/
        for (String node : nodes) {
            NodeExtra minExtra = null;
            int min = Integer.MAX_VALUE;
            /**
             * 找出起始点当前路径最短的节点
             */
            for (String notVisitedNode : nodes) {
                NodeExtra extra = nodeExtras.get(notVisitedNode);
                if (!extra.visited && extra.distance < min) {
                    min = extra.distance;
                    minExtra = extra;
                }
            }

            /**
             * 更新找到的最短路径节点的extra信息(获取的标志、路径信息)
             */
            if (minExtra != null) {
                minExtra.visited = true;
                minExtra.path = nodeExtras.get(minExtra.preNode).path + " -> " + minExtra.nodeName;
                current = minExtra;
            }

            /**
             * 并入新查找到的节点后,更新与其相关节点的最短路径中间结果
             * if (D[j] + arcs[j][k] < D[k]) D[k] = D[j] + arcs[j][k]
             */
            Set<String> successors = graph.successors(current.nodeName); //只需循环当前节点的后继列表即可
            for (String notVisitedNode : successors) {
                NodeExtra extra = nodeExtras.get(notVisitedNode);
                if (!extra.visited) {
                    final int value = current.distance + graph.edgeValueOrDefault(current.nodeName,
                            notVisitedNode, 0);
                    if (value < extra.distance) {
                        extra.distance = value;
                        extra.preNode = current.nodeName;
                    }
                }
            }
        }

        /**
         * 输出起始节点到每个节点的最短路径以及路径的途径点信息
         */
        Set<String> keys = nodeExtras.keySet();
        for (String node : keys) {
            NodeExtra extra = nodeExtras.get(node);
            if (extra.distance < Integer.MAX_VALUE) {
                Log.i(TAG, startNode + " -> " + node + ": min: " + extra.distance
                        + ", path: " + extra.path);
            }
        }
    }

    private static class NodeExtra {
        public String nodeName; //当前的节点名称
        public int distance; //开始点到当前节点的最短路径
        public boolean visited; //当前节点是否已经求的最短路径
        public String preNode; //前一个节点名称
        public String path; //路径的所有途径点
    }

    private static MutableValueGraph<String, Integer> buildGraph1() {
        MutableValueGraph<String, Integer> graph = ValueGraphBuilder.directed()
                .nodeOrder(ElementOrder.insertion())
                .expectedNodeCount(10)
                .build();
        graph.putEdgeValue(V0, V2, 10);
        graph.putEdgeValue(V0, V4, 30);
        graph.putEdgeValue(V0, V5, 100);
        graph.putEdgeValue(V1, V2, 5);
        graph.putEdgeValue(V2, V3, 50);
        graph.putEdgeValue(V3, V5, 10);
        graph.putEdgeValue(V4, V3, 20);
        graph.putEdgeValue(V4, V5, 60);

        return graph;
    }

    private static MutableValueGraph<String, Integer> buildGraph2() {
        MutableValueGraph<String, Integer> graph = ValueGraphBuilder.directed()
                .nodeOrder(ElementOrder.insertion())
                .expectedNodeCount(10)
                .build();

        graph.putEdgeValue(A, B, 10);
        graph.putEdgeValue(A, C, 3);
        graph.putEdgeValue(A, D, 20);
        graph.putEdgeValue(B, D, 5);
        graph.putEdgeValue(C, E, 15);
        graph.putEdgeValue(C, B, 2);
        graph.putEdgeValue(D, E, 11);

        return graph;
    }

    private static <K, V> String format(Map<K, V> values) {
        StringBuilder builder = new StringBuilder();
        builder.append("{");
        Set<K> keys = values.keySet();
        for (K key : keys) {
            builder.append(key).append(":")
                    .append(values.get(key)).append(",");
        }
        if (builder.length()  > 1) {
            builder.deleteCharAt(builder.length() - 1);
        }
        builder.append("}");
        return builder.toString();
    }


    private static <T> String format(Iterable<T> iterable) {
        StringBuilder builder = new StringBuilder();
        builder.append("{");
        for (T obj : iterable) {
            builder.append(obj).append(",");
        }
        if (builder.length()  > 1) {
            builder.deleteCharAt(builder.length() - 1);
        }
        builder.append("}");
        return builder.toString();
    }
}

Floyde

  • 动态规划算法
public class Floyd {
    private static final String TAG = "Floyd";
    public static void test() {
        int vexCount = 4;
        int[][] arcs = new int[vexCount + 1][vexCount + 1];
        int[][] path = new int[vexCount + 1][vexCount + 1];

        /**
         * 初始化图的邻接矩阵
         */
        for (int i = 1; i <= vexCount; i++) {
            for (int j = 1; j <= vexCount; j++) {
                if (i != j) {
                    arcs[i][j] = Integer.MAX_VALUE;
                } else {
                    arcs[i][j] = 0;
                }
                path[i][j] = j;
            }
        }

        /**
         * 输入图的边集
         */
        arcs[1][2] = 2;
        arcs[1][3] = 6;
        arcs[1][4] = 4;
        arcs[2][3] = 3;
        arcs[3][1] = 7;
        arcs[3][4] = 1;
        arcs[4][1] = 5;
        arcs[4][3] = 12;
        print(arcs, vexCount, 0);

        /**
         * floyd核心算法:
         * if arcs[i][k] + arcs[k][j] < arcs[i][j] then
         *      arcs[i][j] = arcs[i][k] + arcs[k][j]
         */
        for (int k = 1; k <= vexCount; k++) {
            for (int i = 1; i <= vexCount; i++) {
                for (int j = 1; j <= vexCount; j++) {
                    if (arcs[i][k] < Integer.MAX_VALUE && arcs[k][j] < Integer.MAX_VALUE) {
                        final int d = arcs[i][k] + arcs[k][j];
                        if (d < arcs[i][j]) { //经过k点时i到j的距离比不经过k点的距离更短
                            arcs[i][j] = d; //更新i到j的最短距离
                            path[i][j] = path[i][k]; //更新i到j经过的最后一个点为k点
                        }
                    }
                }
            }
            print(arcs, vexCount, k);
        }

        printPath(arcs, path, vexCount);
    }

    private static void print(int arcs[][], int vexCount, int index) {
        Log.d(TAG, "print array step of " + index + ":");
        for (int i = 1; i <= vexCount; i++) {
            StringBuilder builder = new StringBuilder();
            for (int j = 1; j <= vexCount; j++) {
                if (arcs[i][j] < Integer.MAX_VALUE) {
                    builder.append(String.format("%5d", arcs[i][j])).append(" ");
                } else {
                    builder.append(String.format("%5s", "∞")).append(" ");
                }
            }
            builder.append("\n");
            Log.d(TAG, builder.toString());
        }
    }

    private static void printPath(int arcs[][], int path[][], int vexCount) {
        Log.d(TAG, "print path:");
        int temp;
        for (int i = 1; i <= vexCount; i++) {
            StringBuilder builder = new StringBuilder();
            for (int j = 1; j <= vexCount; j++) {
                builder.append(i).append("->").append(j)
                    .append(", weight: "). append(arcs[i][j]).append(":").append(i);
                temp = path[i][j];
                while(temp != j) {
                    builder.append("->").append(temp);
                    temp = path[temp][j];
                }
                builder.append("->").append(j).append("\n");
            }
            Log.d(TAG, builder.toString());
        }
    }
}

相关文章

  • 图的应用-最短路径求解

    图的最短路径   图的最短路径是一个起点到一个终点之间最短的路径。  用于解决最短路径问题的算法被称做“最短路径算...

  • Yen的K条最短路径算法(KSP)

    一、问题介绍 1.求K条最短路径的必要性 最短路径问题分为: 单源最短路径 所有顶点对间的最短路径 共同的缺陷:这...

  • 最短路径算法

    最短路径算法可以分为两类:单源最短路径问题:从某固定源点出发,求其到所有其他顶点的最短路径。多源最短路径问题:求任...

  • 最短路径 之 Dijkstra 算法

    • 最短路径 之 Floyd 算法• 最短路径 之 Bellman 算法 Dijkstra算法是用于求解单源最短路...

  • 数据结构第二季 Day11 图 Kruskal算法、Dijkst

    一、最短路径基础知识 1、最短路径的定义是什么? 最短路径(Shortest Path):两顶点之间权值之和最小的...

  • 图 求解最短路径 时间复杂度 空间复杂度 单源最短路径 多源最短路径 条数最短(点权为1) 边权之和最小或最大(花...

  • 最短路径问题

    无权图单源最短路径 有权图单源最短路径 有权图单源最短路径和无权图最短路径不一样,不能单从节点数来看,比如上图中,...

  • 最短路径

    最短路径 最短路径:http://baike.baidu.com/view/349189.htmDijkstra算...

  • 算法之「迪杰斯特拉(Dijkstra)算法」

    最短路径 生活中,我们常常会面临着对路径的最优选择问题,可能是路程最短,也可能是时间最短,这个的最短路径就类似路程...

  • 数据结构与算法-图的最短路径Dijkstra算法&Floyd算法

    最短路径 最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。在...

网友评论

      本文标题:最短路径

      本文链接:https://www.haomeiwen.com/subject/pamwcqtx.html