最短路径的Floyd与Dijkstra算法

来源:互联网 发布:孙叔公的淘宝店 编辑:程序博客网 时间:2024/06/08 06:02

Floyd算法和Dijkstar算法是用来获得图中两点最短路径的算法。Dijkstar算法最终能够得到一个节点到其他所有节点的最短路径,而Floyd算法最终能够找出每对点之间的最短距离。

Dijkstar算法

算法简介

  Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。Dijkstra一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用OPEN, CLOSE表的方式,这里均采用永久和临时标号的方式。注意该算法要求图中不存在负权回路。

算法描述  (这里描述的是从节点1开始到各点的dijkstra算法,其中Wa->b表示a->b的边的权值,d(i)即为最短路径值)

  1. 置集合S={2,3,...n}, 数组d(1)=0, d(i)=W1->i(1,i之间存在边) or +无穷大(1.i之间不存在边)

  2. 在S中,令d(j)=min{d(i),i属于S},令S=S-{j},若S为空集则算法结束,否则转3

  3. 对全部i属于S,如果存在边j->i,那么置d(i)=min{d(i), d(j)+Wj->i},转2

复杂度分析

  Dijkstra 算法的时间复杂度为O(n^2)

  空间复杂度取决于存储方式,邻接矩阵为O(n^2)

 

问题描述:给定图G,求其顶点t到其他所有点的最短路径。

算法描述:将图所有点的集合S分为两部分,V和S-V。V集合是已经得到最短路径的点的集合,在初始情况下V中只有一个顶点t,S-V是还未得到最短路径点的集合。然后,在每一次迭代过程中取得S-V集中到V集合任一点距离最短的点,将其加到V集合,从V-S集合删除。重复此过程直到S-V集合为空。

时间复杂度:O(|E|+|V|\log|V|)

示例:


 

伪代码:

算法实现

输入输出格式 

       输入格式:

  第1行:一个数n,代表有n个节点

  第2-n+1行:每行n个数,代表图的邻接矩阵,没有边相连为-1

  输出格式:

  第1行:n-1个数,分别是1号节点到2-n号节点的最短路径

Java代码:

 

package com.collonn.algorithm;import java.util.PriorityQueue;/** * 带权有向图的单源最短路径<br/> * Dijkstra算法-(迪杰斯特拉)算法<br/> */public class GrfDijkstra {// 为了矩阵的输出更直观好看一些,本例中约定,路径权值取值范围为:[1,10],权值为999表示无连通// 并假设所有权值的和小于999private final int MAX = 999;// 顶点总数private int total;// 顶点信息private String[] nodes;// 顶点矩阵private int[][] matirx;// 源点到各顶点的距离private int[] dis;// 顶点是否已标记private int[] mark;public GrfDijkstra(int total, String[] nodes) {this.total = total;this.nodes = nodes;this.matirx = new int[total][total];this.dis = new int[total];this.mark = new int[total];}private void printMatrix() {System.out.println("--------- weighted directed matrix ---------");System.out.println("---0---1---2---3---4---5---6---7---8---");System.out.println("---A---B---C---D---E---F---G---H---I---");for (int i = 0; i < this.total; i++) {System.out.print("-" + this.nodes[i] + "|");for (int j = 0; j < this.total; j++) {System.out.print(String.format("%03d", this.matirx[i][j]) + "-");}System.out.print("\n");}System.out.println("--------- weighted directed matrix ---------");}/** * Dijkstra算法-(迪杰斯特拉)算法之迭代实现 *  * @param s *            源点(起点) */public void dijkstra(int s) {// 初始化for (int i = 0; i < this.total; i++) {// 初始化都未标记this.mark[i] = 0;// 给源点的直接邻接点加上初始权值this.dis[i] = this.matirx[s][i];}// 将源点s加入已标记this.mark[s] = 1;// 顶点到自身的距离为0this.dis[s] = 0;// 临时最短距离int min = -1;// 临时最短距离的顶点int k = -1;this.printDis(0, "屌", "初始化");// 除去源点s到自身的距离为0外,还要不断的进行距离修正(源点s到其它顶点(共total-1个)的最短距离)for (int i = 1; i < this.total; i++) {// 从当前最新的,源点到其它各顶点的距离信息数组dis[]中,找到一个没有标记过的,// 并且距离(从源点到该某顶点)最短的顶点min = MAX;for (int j = 0; j < this.total; j++) {if (this.mark[j] == 0 && this.dis[j] < min) {min = this.dis[j];k = j;}}// 标记该顶点this.mark[k] = 1;/** * 距离校正<br/> */for (int j = 0; j < this.total; j++) {if (this.mark[j] == 0 && (this.matirx[k][j] + this.dis[k]) < this.dis[j]) {this.dis[j] = this.matirx[k][j] + this.dis[k];}}this.printDis(i, this.nodes[k], "进行中");}}/** * Dijkstra算法-(迪杰斯特拉)算法之优先队列实现 */public void dijkstraPQ() {// Item是PriorityQueue中元素,实现了Comparable接口,优先队列用此接口进行排序class Item implements Comparable<Item> {// 节点在数组的下标public int idx;// 到改节点的临时最小权值和public int weight;public Item(int idx, int weight) {this.idx = idx;this.weight = weight;}@Overridepublic int compareTo(Item item) {if (this.weight == item.weight) {return 0;} else if (this.weight < item.weight) {return -1;} else {return 1;}}}// 值较小的元素总是在优先队列的头部,值较大的元素总是在优先队列的尾部PriorityQueue<Item> pq = new PriorityQueue<Item>();// 将源点(即起点)加入到优先队列pq.offer(new Item(0, 0));Item itm = null;while (!pq.isEmpty()) {itm = pq.poll();// 图中某节点下标int idx = itm.idx;// 到某节点的临时最小权值和int weight = itm.weight;// 如果该元素还未标记,则更新最小权值各if (this.mark[idx] == 0) {this.dis[idx] = weight;}// 找出该元素(假设A)的所有未标记的邻接点(假设B)// 则,源点到B的距离可表示为:(源点到A的距离) + (A到B的距离)// 将源点到B的距离加入到优先队列中for (int i = 0; i < this.total; i++) {if (this.mark[i] == 0) {pq.offer(new Item(i, this.dis[idx] + this.matirx[idx][i]));}}}}private void printDis(int i, String node, String pre) {System.out.print("\n" + pre + "," + node + "," + i + "--->");for (int t = 0; t < this.dis.length; t++) {System.out.print(t + ",");}System.out.print("\n" + pre + i + "--->");for (int t : this.dis) {System.out.print(t + ",");}System.out.print("\n");}// 初始化图数据// 0---1---2---3---4---5---6---7---8---// A---B---C---D---E---F---G---H---I---private void initGrf() {// 初始化矩阵为最大值(各节点都不连通)for (int i = 0; i < this.total; i++) {for (int j = 0; j < this.total; j++) {if (i == j) {this.matirx[i][j] = 0;} else {this.matirx[i][j] = MAX;}}}// 手动设置有向路径// A->B, A->E, A->Dthis.matirx[0][1] = 2;this.matirx[0][4] = 3;this.matirx[0][3] = 1;// B->Cthis.matirx[1][2] = 2;// C->Fthis.matirx[2][5] = 1;// D->E, D->Gthis.matirx[3][4] = 5;this.matirx[3][6] = 2;// E->F, E->Hthis.matirx[4][5] = 6;this.matirx[4][7] = 1;// F->Ithis.matirx[5][8] = 3;// G->Hthis.matirx[6][7] = 4;// H->F, H->Ithis.matirx[7][5] = 1;this.matirx[7][8] = 2;}public static void main(String[] args) {String[] nodes = new String[] { "A", "B", "C", "D", "E", "F", "G", "H", "I" };GrfDijkstra grf = new GrfDijkstra(nodes.length, nodes);grf.initGrf();grf.printMatrix();System.out.println();System.out.println("------ Dijkstra算法-(迪杰斯特拉)算法之迭代开始 ------");grf.dijkstra(0);grf.printDis(0, "屌", "最终值");System.out.print("\n");System.out.println("------ Dijkstra算法-(迪杰斯特拉)算法之迭代结束 ------");System.out.println();System.out.println("------ Dijkstra算法-(迪杰斯特拉)算法之优先队列开始 ------");grf.dijkstraPQ();grf.printDis(0, "屌", "最终值");System.out.print("\n");System.out.println("------ Dijkstra算法-(迪杰斯特拉)算法之优先队列结束 ------");}}

 Floyd算法

问题描述:给定图G,得到每个点对的最短距离。

算法描述:Floyd算法是一个动态规划算法,最初矩阵A0是图的邻接矩阵,AK矩阵表示从i到j的最短路径,这些路径不能能通过大于K的节点,最终的矩阵AN就是想要得到的矩阵了。那么AK矩阵与A(K+1)矩阵有什么关系呢?关系就是A(K+1)[i,j]=min(A(K)[i,j],A(K)[i,k]+A(K)[k,j]),也就是看加上K点后,是不是能找到更短的距离。

时间复杂度:O(|V|^3) 顶点数的三次方。

示例:一上面的图为例子,下面展示了矩阵系列的建立过程:

Java代码:

 

原创粉丝点击