BellmanFord算法
- Bellman-Ford算法是一种用来求解带负权边的图中单源最短路径的经典算法。它可以应用于包含负权边和环路的图,相比于Dijkstra算法,适用范围更广。
- 算法的基本思想:是通过对每条边进行松弛操作,逐步迭代更新节点到源节点的最短路径估计值。算法从源节点开始,将源节点到其他所有节点的初始最短路径估计值置为无穷大,然后逐步优化这些估计值,直到收敛为止
- 算法实现:以下图为例(java代码实现)
代码实现如下
// 该算法可以处理权重中含有负的边
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);
}
}
输出结果
与预期相符
总结一下
总结来说,Bellman-Ford算法是一种适用于带有负权边的图的单源最短路径算法,通过迭代更新节点的最短路径估计值,并可以检测负权环的存在。
优化
代码优化请看下一篇文章,本人能力有限,我非常愿意听取您的宝贵意见和建议,请您不吝赐教。我相信您的观点和见解对我来说非常重要,能够帮助我不断提升和改进。期待能够收到您的反馈,非常感谢!