Graph Algorithms (Part 2.0): The Bellman-Ford Algorithm [Concept]

Hello 0x00sec people! It’s @oaktree once again coming at you with another tutorial. This time, it’s about the Bellman-Ford Algorithm.

This algorithm is very similar to Dijkstra’s Algorithm from last time, yet it diverges in that it is designed to handle negative edge weights, which are “negative distances,” in a way.

The use of the algorithm is two-fold: determine the shortest path between a starting node and all other nodes in a graph; and, determine if there are any negative cycles. A negative cycle is when traversing the same path again makes the distance smaller. This would continue and approach negative infinity if we kept traversing the same negative cycle.


Applications

I’m paraphrasing Wikipedia here. This algorithm is used in the Routing Information Protocol (cough @airth). This allows each node in a network to know how far every other node is. Each node calculates the distance between it and all other reachable nodes, and then sends that information to all the other nodes, so that all the nodes can update their information if/when a shorter path is discovered.


#Procedure

Image from this guy’s wonderful Youtube video on the subject. You should all go watch that video and give him a like.

Alright: Here’s an example of a graph with negative edge weights. Our algorithm is going to go through and find the shortest distance to each node from a starting node. For this example, our starting node will be S. Once it does, it’ll go over it one more time. Any distances that get smaller will do so because of a negatively-weighted edge. When this happens, we have detected a negative cycle.


Time Complexity

To ensure that we have found the shortest path, we’ll iterate through the graph |V| - 1 times, where V is the number of vertices. Then, we’ll iterate through one last time to find the negative cycles.

All in all, the time complexity boils down to O(|V|*|E|), where E is the number of edges.


Pseudocode

bellman(start, graph, distances):
    for_each vertex in graph:
        distances[vertex] = infinity
    
    distances[start] = 0

    previous = Array of graph.vertex_count elements

    // find the minimum distances
    (graph.vertex_count - 1) times:
        for_each node in graph:
            for_each neighbor of node:
                if distances[neighbor] >  distances[node] + edge(node,neighbor):
                    distances[neighbor] = distances[node] + edge(node,neighbor)
                    previous[neighbor] = node
                

    // go through one last time to check for negative cycles
    for_each node in graph:
        for_each neighbor of node:
            if distances[neighbor] >  distances[node] + edge(node,neighbor):
                 print "negative cycle found between " + node + " and " + neighbor + "\n"

As you can see, the first thing we do is set each distance to infinity. Then, we make sure that distances[start] = 0 because the distance between a node and itself should ideally be 0.

I also made an array called previous just to keep track of the path – not that it matters all that much for finding distances, though.

The next thing to do is iterate through the graph |V| - 1 times. We go through each node’s neighbors and see if we can find a better distance. If we do, we also update the previous element corresponding to the neighbor.

After all of those |V| - 1 times (it can be optimized, but I wouldn’t want to cause confusion), we loop through once more to see if there are any negative cycles. |V| - 1 times is enough iterations to determine the shortest distance, so if it’s shorter now it must be due to a negative edge weight, a negative cycle.


Conclusion

That’s about all the algorithm does. In Part 2.1 (I really like to stick with my conventions), we’ll write out some C++ code to perform the algorithm.

Graph ya’ later,
@oaktree

P.S. If you have Sublime Text 2/3, get the DarkKorokai color scheme.

4 Likes

Good old RIP, the root of every routing protocol. Since RIP is rarely used in a company’s network, I assume Bellman-Ford isn’t the most efficient algo to get the job done and that’s why RIP’s implementation has been fading away I guess. Good stuff oakey!

1 Like

You’re right. It is not the most efficient, because it takes a while for the results of the algorithm on one node to reach all the other ones. This can cause some messages to loop in the meantime.

This topic was automatically closed after 30 days. New replies are no longer allowed.