Bellman-Ford算法求解单源最短路径Java实现

来源:互联网 发布:淘宝买家信誉快速 编辑:程序博客网 时间:2024/05/16 17:47

Bellman-Ford算法解决的是一般情况下的单源最短路径问题,在这里,边的权重可以是负值。如果存在一个从源结点可以到达的权重为负值的环路,则算法将还会告诉我们 不存在解决方案,否则算法将给出最短路径和它们的权重。该算法用到了松弛(relaxation)技术。对于每一个结点v来说,我们维持两个属性,一个是v.d,用来记录从源结点s到结点v的最短路径权重的上界,我们称v.d为s到v的最短路径估计。另一个是v.π,用来记录当前从源结点s到结点v的最短路径中v的前驱结点。对于所有的结点将这两个属性进行初始化,v.d设置为无穷大,v.π设置为不存在(NIL),将源结点的s.d设置为0 。

则对一条边(u,v)的松弛过程为:首先测试一下是否可以对从s到v的 最短路径进行改善。测试的方法是,将从结点s到u之间的最短路径距离加上u与v之间的边的权重,并与当前的s到v的最短路径估计进行比较,如果前者更小,则对v.d和v.π进行更新。松弛可能降低最短路径的估计值v.d并更新v的前驱属性v.π 。

而Bellman-Ford算法就是对每一条边进行|V|-1次的松弛操作。其伪代码如下


下图 是一个Belllman-Ford算法求解单源最短路径的一个例子。


以下是Java代码的 实现

package test6;/** * 边 * @author sdu20 * */public class Edge {private int v1;private int v2;private int weight;public Edge(int v1,int v2,int weight){this.v1 = v1;this.v2 = v2;this.weight = weight;}public boolean equals(Edge edge){return this.v1==edge.getV1() && this.v2==edge.getV2() &&this.weight == edge.getWeight();}public int getV1(){return v1;}public int getV2(){return v2;}public int getWeight(){return weight;}public String toString(){String str = "[ "+v1+" , "+v2+" , "+weight+" ]";return str;}}

package test6;import java.util.*;/** * 图类 * @author sdu20 * */public class Graph {private LinkedList<Edge>[] edgeLinks;private int vNum;//顶点数private int edgeNum;//边数private int[] distance;//存放v.dprivate int[] prenode;//存放前驱节点public static final int INF = 10000;//无穷大public static final int NIL = -1;//表示不存在public Graph(int vnum){this.vNum = vnum;edgeLinks = new LinkedList[vnum];edgeNum = 0;distance = new int[vnum];prenode = new int[vnum];for(int i = 0;i<vnum;i++)edgeLinks[i] = new LinkedList<>();}public void insertEdge(Edge edge){int v1 = edge.getV1();edgeLinks[v1].add(edge);edgeNum++;}public void bianli(){System.out.println("共有 "+vNum+" 个顶点, "+edgeNum+" 条边");for(int i = 0;i<vNum;i++){LinkedList<Edge> list = (LinkedList<Edge>) edgeLinks[i].clone();while(!list.isEmpty()){Edge edge = list.pop();System.out.println(edge.toString());}}}/** * 对最短路径估计和前驱节点进行初始化 * @param start */public void INITIALIZE_SINGLE_SOURCE(int start){for(int i = 0;i<vNum;i++){distance[i] = INF;prenode[i] = NIL;}distance[start] = 0;}/** * 松弛 * @param edge */public void RELAX(Edge edge){int v1 = edge.getV1();int v2 = edge.getV2();int w = edge.getWeight();if(distance[v2]>distance[v1]+w){distance[v2] = distance[v1]+w;prenode[v2] = v1;}}/** * Bellman-Ford算法实现 * @return 是否没有负环 */public boolean BELLMAN_FORD(int start){INITIALIZE_SINGLE_SOURCE(start);for(int i = 0;i<vNum-1;i++){for(int j = 0;j<vNum;j++){LinkedList<Edge> list = (LinkedList<Edge>) edgeLinks[j].clone();while(!list.isEmpty()){Edge edge = list.pop();RELAX(edge);}}}for(int i = 0;i<vNum;i++){LinkedList<Edge> list = (LinkedList<Edge>) edgeLinks[i].clone();while(!list.isEmpty()){Edge edge = list.pop();int v1 = edge.getV1();int v2 = edge.getV2();int w = edge.getWeight();if(distance[v2]>distance[v1]+w)return false;}}return true;}/** * 显示结果 */public void showResult(){Stack<Integer>[] routes = new Stack[vNum];for(int i = 0;i<vNum;i++){routes[i] = new Stack<>();int j = i;while(j != NIL){routes[i].push(j);j = prenode[j];}System.out.print(i+"("+distance[i]+") : ");while(!routes[i].isEmpty()){int k = routes[i].pop();System.out.print("-->"+k);}System.out.println();}}public int[] getDistance(){return distance;}public int[] getPrenode(){return prenode;}}

package test6;public class Main {public static void main(String[] args) {// TODO Auto-generated method stubint vnum = 5;Graph graph = new Graph(vnum);Edge[] edges = new Edge[10];edges[0] = new Edge(0,1,6);edges[1] = new Edge(0,3,7);edges[2] = new Edge(1,2,5);edges[3] = new Edge(1,3,8);edges[4] = new Edge(1,4,-4);edges[5] = new Edge(2,1,-2);edges[6] = new Edge(3,2,-3);edges[7] = new Edge(3,4,9);edges[8] = new Edge(4,0,2);edges[9] = new Edge(4,2,7);for(int i = 0;i<10;i++){graph.insertEdge(edges[i]);}graph.bianli();boolean success = graph.BELLMAN_FORD(0);if(success){System.out.println("没有负环");graph.showResult();}else{System.out.println("存在负环");}}}

运行截图如下所示