0:03

Now we'll look for, at Dijkstra's algorithm for finding shortest paths in

graphs with non-negative edge weights. Dijsktra is a famous figure in computer

science. And you can amuse yourself by reading some

of the things that he wrote. He was a very prolific writer, and, kept

notebooks. And then here really some of his, famous

quotes. Now, you need to may know something about,

old languages to appreciate some of these. For example, COBOL was one of the first

business oriented languages, programming languages and it tried to, make it so that

programs kind of read like English language sentences.

But purists in computer science, such as Dijkstra really didn't like that language

as you can tell, The use of COBOL cripples the mind.

It's teaching should therefore be regarded as a criminal offense.

Actually, when I first came to Princeton and was setting up the department here,

One of, there was a big donor, who actually, wanted to have me fired and the

department closed down because we wouldn't teach COBOL.

I didn't know about Dijkstra's quote at that time,

I wish I had. And there's some other opinions that

Dijkstra had. You can amuse yourself on the web, reading

some of his writing, But he was, here's another one that's

actually pretty relevant today. Object-oriented programming is an

exceptionally bad idea that could only have originated in California.

Dijkstra worked in Texas, the University of Texas for a while, and of course, came

from the Netherlands. Okay.

But, Dijkstra, did, invent, a very, very important algorithm, that's very widely

used for solving the shortest paths problem.

It's the one that's in your maps app and in your, car, and many, many other

applications. So let's take a look at how that algorithm

works. It's a very simple algorithm.

We, consider, what we're going to do is consider the vertices

In increasing order of their distance from the source.

So and a way we're going to do that is take the next vertex, add it to the tree

and relax all the edges that point from that vertex.

So let's talk about it in terms of a demo and then we'll look at the code.

2:47

So our mandate is to consider vertices in increasing order of distance from the

source. So, our source is zero in this case so

what vertices are closest to the source? Well, we can look at the edges that point

from that vertex. Well, start out with vertex is zero, is

the distance zero from the source, so we pick it.

Then we add that vertex to the shortest paths tree, and relax all its edges.

And relaxing all the edges pointing from zero in this case is just going to uptake

the, this two and edgeTo entries for five, eight, nine.

So in this case, this says that the shortest path from zero to one is to go

along zero, one and that's distance five and from zero to four, it's to go along

zero, four and that's distance nine, And zero to seven, let's go take it zero,

seven that's distance eight. And the edge weights are positive.

We're not going to find a shorter path to anyone, of what,

Sorry. The edge weights are positive and those

are the shortest paths that we know so far to the vertices.

Now, the first key point of the algorithm is take the closest one.

If you take the closest one, in this case, it's one, Then we know we're not going to

find a shorter, shorter path to one. The only other way to go out of zero is to

take one of these other edges, and they're longer.

So, and all the edge weights are positive. So we're not going to find a shorter way

from zero to one, than to take the edge, 0-1.

So that means that edge 0-1 is on the shortest path tree,

That's what the algorithm says. Take the next closest vertex to the

source. in this case, it's one. And then,

We're going to add that edge, that vertex to the tree.

And relax all the edges that point from that.

So now both zero and one are on the tree, so now let's look at the edges pointing to

that and we have to relax each one of those.

So in this case if you go from one to four, Then we look at four, we know a path

of length nine. And one to four doesn't give us a shorter

path, so we leave that edge alone. One to three gives us a shorter path to

three which is going to be twenty, cuz you went from zero to one, and then one to

three is of length twenty. And one to two, also, we didn't know a way

to two, But now we know now we know one, or better one is seventeen.

So that completes the relaxation of all the edges pointing from one.

So now we have zero and one on the tree, And.

5:44

We would, consider next, The next closest vertex to the source.

So what we have in this two is the shortest paths to all the vertex, vertices

that we've seen so far and this one says that the we've been to the zero and one so

the next closest one is seven, which is distance eight.

So we are going to choose vertex seven. And again, that's the shortest path we've

seen so far, we are not going to find a shorter one cuz to get to every other

vertex is longer. and so, we know it's on the shortest paths tree, and now we're

going to relax all the edges pointing from seven.

In this case, both of them, the one from seven to two, gives us a shorter way to

two than what we knew before, and the one from seven to five gives us a shorter way

to five than we knew before. Well, we hadn't been to five before.

So that relaxes seven, so now seven is on the shortest paths tree.

So now 4's the next closest path vertex to the source.

From the edge zero, four which is of length nine.

So that's the one that we're going to pick next for the tree.

We're not going to find a shorter path there,

And we relax, relax along all its edges. In this case, we find a shorter path to

five than we knew before and a shorter path to six, well, we visit six for the

first time. Okay, so that's four, so now we just have

to worry about two, three, five, and six, and five is the one over there, and so we

select vertex five, Relax along its edges. In this case those edges both give us

better paths than we knew before. So now we're left with three vertices, and

two is the winner. This is the two from the sources fourteen,

To three, it's twenty and to six, it's 26. Relax it's edges, and it gives us again,

new shorter paths to both three and six. And then the last, this next to last step

is to pick three and that does not give us a new way to six, and then finally we pick

six. And then we now know,

The shortest path to all the vertices from vertex zero.

If we just take the edgeTo edges, That's from one, to one you take zero, to

five you take two, And so forth you get the shortest paths tree and that gives the

shortest way to get from the source to every vertex.

That's a simulation of Dijkstra's algorithm.

8:36

Here's a demo of Dijsktra's algorithm running in a large digraph.

So the source is the protects the center with the open circle and you can see it

considers the vertices in the graph in order of their distance from the source.

Now you can see this is maybe like a lake in the middle of the graph,

And so it's not going to move on from those vertices.

It's going to take a little while to get around the lake.

And again, if, this visualization is produced by our code,

Then it, and it gives a very, natural feeling for the way that the algorithm

works, This, in principle. And I think, in fact,

in many cases, is what your, car does when you turn the map system on,

It computes the shortest path to everywhere,

And then it's all ready when you ask for a certain place, how to get there.

So here's just, starting from another point in the graph.

You have, if you happen to live at a corner of the Earth, then it's going to be

slightly longer to get to the other corner.

And, a nice feeling for how the algorithm gets its job done.

Again, when it gets into those blank areas, it takes a little while to get over

to the other side. And of course if we had islands, if we had

little roads in the middle there that were not connected,

Then we know where to get to them from the source and we wouldn't see them.

And that's fine for the way our algorithm works.

We just leave that out of the demo and the proof to avoid adding an extra comment

about that for every algorithm. That's a visualization of Dijkstra's

algorithm on a large graph. So, so how do we prove it's correct?

Well, essentially we've prove that it's an instance of the generic algorithm.

So, first thing is that every edge is relaxed exactly once.

Every time we, everytime we put a vertex onto the tree, we relax all the edges that

come from that vertex and we never reconsider the vertex.

And what does relaxation do? Relaxation ensures that after the

relaxation, either way there was before, afterwards, you have the distance to w is

less than or equal the distance to v plus e to the, e plus the way to the edge.

Either it's equal cuz we just made it that way, or it's less than it was before and

the edge was not relevant. And this inequality is going to hold for

every an, entry for every edge corresponding to every edge, for just two

entries corresponding to every edge because number one, the, these two values

are always increasing. We never I'm sorry, we're always

decreasing. The only thing we ever change, only reason

we ever change distTo w is to make it smaller.

If we, if we found an edge that would make it bigger we ignor that edge,

So it's always decreasing. So when we change distTo w, we're not

going to make that inequality holds. We're just going to make it better.

And this distTo v is not going to change at all.

Once we relax an edge from a vertex, we're done with that vertex.

We're not going to process that at all. So, then when we're done we have the

optimality conditions hold that exactly is the optimality condition.

And, not only that, we have a path from the source to every vertex.

So that's the correctness proof for Dijkstra's algorithm based on the

optimality conditions. Here's the code.

It's similar to code that we've seen before.

We're going to use the indexed priority queue that allows us to implement the

decreased key operation. And we have our edgeTo and distTo arrays

that are part of the shortest paths computation and the goal of the shortest

paths computation. So we initialized the constructor,

initializes those rays and including the Index

Minimum PQ. and we start out with all the distances infinity except for the distance

of the source is zero. We put the source on the priority Q and

then what we're going to do is take the, Edge that closest to the source off the

priority. That's on the priority queue off and then

relax all the edges that are adjacent to that, so I'm using our standard iterator

to get all the edges that emanate from that vertex and relax them. And then the

relax code is just like the code that was showed when describing relaxation, except

that it also updates the priority queue. If the, vertex, that, that edge goes to is

on the priority queue, it gives a new shorter way to get to that,

So we have to, decrease the key on the priority queue,

Cuz if it's not on the priority queue, we insert it,

And that's it. That's a complete implementation, of

Dijsktra's algorithm using modern data structures.

Now, this algorithm might seem very familiar than, if you've been paying

attention. It's essentially the same algorithm as

Prim's algorithm. The difference is that, in both cases,

we're building what's called a spanning tree of the graph.

But in Prim's algorithm, we take a vertex that, that's not on the tree using the

rule of let's take the vertex that's closest to the tree, anywhere on the tree,

Closest to some vertex on the tree. For Dijsktra's algorithm, we take next,

the vertex that's closest to the source through a path, they go through a tree and

then into a non-tree vertex. That's the difference and the differences

in the code have to do with the fact that Prim's algorithm is for an undirected

graph, Dijsktra's algorithm is for a directed graph,

But essentially, they're the same algorithm.

And actually, several of the algorithms that we've talked about are in this same

family. They compute a spanning tree.

I have, you, you have a tree that takes care of where that records where you've

been in the graph, From every vertex, back to where you

started. Then you used different rules for choosing

which vertex to add next. For breadth-first search, you use a Q, for

depth-first search, you use something like a stack and then you have to decide what

to do, if you encounter a vertex that you've been to before.

But many graph algorithms use this same basic idea.

So in particular, when we are talking about what the running time of Dijsktra's

algorithm, it depends on what priority Q the implementation we use,

And it's the same considerations as for Prim's algorithm.

We have V insert operations, every vertex goes on to the priority queue. V

delete-min, every vertex comes off the priority queue. and for every edge, in the

worst case, we could compute decrease-key operation.

So, the original implementations of Dijsktra's algorithm used an unordered

array, Which would mean that it would take time

proportional to V to find the minimum, To find the vertex closest to the source.

17:30

decrease-key. But still, we get a total running time of

E log V, Which makes it feasible.

And just as with Prim's algorithm, by using a implementation of the priority

queue that can do a faster decrease-key, you can get a faster algorithm.

And in, in practice something like a 4-way hit is going to give quite a fast

algorithm. And so, more expensive to insert and t-,

to insert but much faster to delete min in decrease key.

And again, there's a theoretical data structure that's not useful in practice.

It gets the running time down to E + V log V.

Of course, if your graph, graph is dense, And again, the examples I used, they're

not. The array implementation is optimal, we

can't do any better. We have to go through all the edges and

might as well find the minimum, at the same time.

But in, in, in practice, people use binary heaps, for sparse graphs.

I maybe going to four way, If, the performance is really critical.

The bottom line is, we have, extremely efficient implementations for the huge

graphs that arise in practice nowadays.