# Shortest Path Faster Algorithm

The Shortest Path Faster Algorithm (SPFA) is an improvement of the Bellman–Ford algorithm which computes single-source shortest paths in a weighted directed graph. The algorithm is believed to work well on random sparse graphs and is particularly suitable for graphs that contain negative-weight edges.[1] However, the worst-case complexity of SPFA is the same as that of Bellman–Ford, so for graphs with nonnegative edge weights Dijkstra's algorithm is preferred.[2] The SPFA algorithm was published in 1994 by Fanding Duan.[3]

## Algorithm

Given a weighted directed graph ${\displaystyle G=(V,E)}$ and a source vertex ${\displaystyle s}$, the SPFA algorithm finds the shortest path from ${\displaystyle s}$, to each vertex ${\displaystyle v}$, in the graph. The length of the shortest path from ${\displaystyle s}$, to ${\displaystyle v}$ is stored in ${\displaystyle d(v)}$ for each vertex ${\displaystyle v}$.

The basic idea of SPFA is the same as Bellman–Ford algorithm in that each vertex is used as a candidate to relax its adjacent vertices. The improvement over the latter is that instead of trying all vertices blindly, SPFA maintains a queue of candidate vertices and adds a vertex to the queue only if that vertex is relaxed. This process repeats until no more vertex can be relaxed.

Below is the pseudo-code of the algorithm.[4] Here ${\displaystyle Q}$ is a first-in, first-out queue of candidate vertices, and ${\displaystyle w(u,v)}$ is the edge weight of ${\displaystyle (u,v)}$.

A demo of SPFA based on Euclidean distance. Red lines are the shortest path covering (so far observed). Blue lines indicate where relaxing happens, i.e., connecting ${\displaystyle v}$ with a node ${\displaystyle u}$ in ${\displaystyle Q}$, which gives a shorter path from the source to ${\displaystyle v}$.
procedure Shortest-Path-Faster-Algorithm(G, s)
1    for each vertex vs in V(G)
2        d(v) := ∞
3    d(s) := 0
4    offer s into Q
5    while Q is not empty
6        u := poll Q
7        for each edge (u, v) in E(G)
8            if d(u) + w(u, v) < d(v) then
9                d(v) := d(u) + w(u, v)
10                if v is not in Q then
11                    offer v into Q

The algorithm can also be applied to an undirected graph by replacing each undirected edge with two directed edge of opposite directions.

## Average-case performance

For a random graph, the empirical average time complexity is ${\displaystyle O(|E|)}$[3], although this algorithm is not proved to have that average runtime.

## Worst-case performance

Following is a way to construct a data to defeat this algorithm (without queue optimization?).[1] Suppose one wants the shortest path from vertex 1 to vertex ${\displaystyle n}$. Then we can add edge ${\displaystyle (i,i+1)}$ with a small random weight for ${\displaystyle 1\leq i (thus the shortest path should be 1-2-...-${\displaystyle n}$), and randomly add ${\displaystyle 4n}$ other heavy edges. For this case, the SPFA algorithm will be very slow.

## Optimization techniques

The performance of the algorithm is strongly determined by the order in which candidate vertices are used to relax other vertices. In fact, if ${\displaystyle Q}$ is a priority queue, then the algorithm pretty much resembles Dijkstra's. However, since a priority queue is not used here, two techniques are sometimes employed to improve the quality of the queue, which in turn improves the average-case performance (but not the worst-case performance). Both techniques rearranges the order of elements in ${\displaystyle Q}$ so that vertices closer to the source are processed first. Therefore, when implementing these techniques, ${\displaystyle Q}$ is no longer a first-in, first-out queue, but rather a normal doubly linked list or double-ended queue.

Small Label First (SLF) technique (first proposed by Bertsekas in Networks, Vol. 23, 1993, pp. 703-709). In line 11, instead of always pushing vertex ${\displaystyle v}$ to the end of the queue, we compare ${\displaystyle d(v)}$ to ${\displaystyle d{\big (}{\text{front}}(Q){\big )}}$, and insert ${\displaystyle v}$ to the front of the queue if ${\displaystyle d(v)}$ is smaller. The pseudo-code for this technique is (after pushing ${\displaystyle v}$ to the end of the queue in line 11):

procedure Small-Label-First(G, Q)
if d(back(Q)) < d(front(Q)) then
u := pop back of Q
push u into front of Q

Large Label Last (LLL) technique (first proposed by Bertsekas, Guerriero, and Musmanno in JOTA, Vol. 88, 1996, pp. 297-320). After line 11, we update the queue so that the first element is smaller than the average, and any element larger than the average is moved to the end of the queue. The pseudo-code is:

procedure Large-Label-Last(G, Q)
x := average of d(v) for all v in Q
while d(front(Q)) > x
u := pop front of Q
push u to back of Q

## References

1. ^ a b About the so-called SPFA algorithm
2. ^ SPFA算法
3. ^ a b Duan, Fanding (1994), "关于最短路径的SPFA快速算法", 西南交通大学学报, 29 (2): 207–212
4. ^ http://codeforces.com/blog/entry/16221