数据结构(Java版实现BellmanFord算法)

27 阅读2分钟

BellmanFord算法

  • Bellman-Ford算法是一种用来求解带负权边的图中单源最短路径的经典算法。它可以应用于包含负权边和环路的图,相比于Dijkstra算法,适用范围更广。
  • 算法的基本思想:是通过对每条边进行松弛操作,逐步迭代更新节点到源节点的最短路径估计值。算法从源节点开始,将源节点到其他所有节点的初始最短路径估计值置为无穷大,然后逐步优化这些估计值,直到收敛为止
  • 算法实现:以下图为例(java代码实现) 图片.png

代码实现如下

// 该算法可以处理权重中含有负的边
public class BellmanFord {
    public static void main(String[] args) {
        Vertex v1 = new Vertex("v1");
        Vertex v2 = new Vertex("v2");
        Vertex v3 = new Vertex("v3");
        Vertex v4 = new Vertex("v4");

        v1.edges = Stream.of(new Edge(v2,2),new Edge(v3,1)).collect(Collectors.toList());
        v2.edges = Stream.of(new Edge(v3,-2)).collect(Collectors.toList());
        v3.edges = Stream.of(new Edge(v4,1)).collect(Collectors.toList());
        v4.edges = new ArrayList<>();

        // 表示这个图
        List<Vertex> graph = Stream.of(v1,v2,v3,v4).collect(Collectors.toList());
        bellmanFord(graph,v1);
        // 输出结果验证
        for (Vertex vertex : graph) {
            System.out.println(vertex);
        }
    }

    /**
     * 思路:根据顶点数进行确定遍历次数。
     * 然后,遍历所有顶点,内层在遍历每一个顶点的时候就进行遍历每一条边
     * 如果边的起始顶点+权重 < 终止顶点的dish,则进行更新
     * 以此类推,遍历所有的边,就可以得到到达每个顶点的最短路径
     * @param graph
     * @param source
     */
    private static void bellmanFord(List<Vertex> graph, Vertex source) {
        source.dist = 0;
        int size = graph.size(); // n个顶点,遍历n-1次
        for (int i = 0; i < size - 1; i++) {
            // 遍历所有边
            for (Vertex start : graph) {
                for (Edge edge : start.edges) {
                    Vertex end = edge.linked;
                    if (start.dist != Integer.MAX_VALUE && start.dist + edge.weight < end.dist){
                        // 进行更新
                        end.dist = start.dist + edge.weight;
                    }
                }
            }
        }

    }
}

附上图的顶点类

class Vertex{
    String name; // 表示顶点的名称
    List<Edge> edges; // 表示这个顶点的边的集合

    boolean visited;  // 表示这个节点是否被访问过 默认为false
    //入度: 拓扑排序需要  默认为零
    int  in_Degree;
    int status ; // 状态     0未访问      1访问中      2访问过              用在拓扑排序中

    int dist = INF;       // 表示每一个顶点当前的距离值,用于求最短路径里面
    static final Integer INF = Integer.MAX_VALUE;

    // 用于记录最短路径中当前节点的上一个节点是谁
    Vertex pred = null;



    public Vertex(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return name+"("+dist+")";
    }

图的边类

class Edge{
    Vertex linked; // 表示这条边所指向的顶点
    int weight; // 表示边的权重


    // 返回一个边的对象
    public Edge(Vertex linked, int weight) {
        this.linked = linked;
        this.weight = weight;
    }
    // 返回一个边的对象
    public Edge(Vertex linked) { // linked,表示这条边指向的顶点
        this(linked,1);
    }
}

输出结果

与预期相符

图片.png

总结一下

总结来说,Bellman-Ford算法是一种适用于带有负权边的图的单源最短路径算法,通过迭代更新节点的最短路径估计值,并可以检测负权环的存在。

优化

代码优化请看下一篇文章,本人能力有限,我非常愿意听取您的宝贵意见和建议,请您不吝赐教。我相信您的观点和见解对我来说非常重要,能够帮助我不断提升和改进。期待能够收到您的反馈,非常感谢!