Skip to content

Commit 5d03c24

Browse files
committed
dijkstras array explanation
1 parent 7a51814 commit 5d03c24

File tree

1 file changed

+52
-6
lines changed

1 file changed

+52
-6
lines changed

docs/graphs.md

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,15 @@ A simple graph may be either connected or disconnected. Unless stated otherwise,
380380

381381
<img src="images/Pasted image 20220222144711.png" alt="Pasted image 20220222144711">
382382

383+
For simple [**connected graphs**](#connected-graph) the amount of edges you can have are striclty bounded by:
384+
385+
$$
386+
\overset{\text{(trees)}}{(|V|-1)}
387+
\le |E| \le
388+
\overset{\text{(complete graphs)}}{\left(\frac{|V|(|V|-1)}{2}\right)}
389+
$$
390+
391+
383392
#### Multigraph
384393

385394
A graph that can have multiple edges between the same pair of nodes. In a road network this could, for example, be used to represent different routes with the same start and end point.
@@ -850,9 +859,14 @@ Finds the shortest **greedy** path via a **[priority queue](computer-science.md#
850859

851860
<img src="images/Dijkstra_Animation.gif" alt="Dijkstra_Animation">
852861

862+
863+
!!! note
864+
865+
For your exam, you don't need to remember how a heap works or the intracacies of the time complexities below. Just remember that there's 2 time complexities and they differ based on implimentation. Maybe learn how to justify one of them in case you need to write a proof.
866+
853867
Worst case performance if using a [priority queue](computer-science.md#priority-queue) (Fibonacci heap version):
854868
$$
855-
\displaystyle O(|E|+|V|\log |V|) \newline
869+
\boxed{\displaystyle O(|E|+|V|\log |V|)} \newline
856870
\text{or equivalently,} \newline
857871
\displaystyle O(|V|\log(|V|+|E|))
858872
$$
@@ -861,8 +875,40 @@ This is because you're initialising each node into `unexplored`. Which is both $
861875

862876
Then considering the inner loop of `for each neighbour N of V do`, you can't immediately think of it as having that automatic coeficcient of $|V|$ because it's in that while loop. Instead, think of it on a higher level and what it's doing overall. That loop is the mechanism for relaxing edges if you find a shorter path. And when you run the algorithm you will see that relaxation is done **once per edge**[^dijkstra-edge]. So that contributes the extra term of $O(|E|)$ for a final time complexity of $O(|V|\log(|V|+|E|)) \equiv O(|E|+|V|\log |V|)$
863877

864-
Worst case performance when using an array:
865-
$$\displaystyle O(|V^2|)$$
878+
<br>
879+
880+
**Worst case performance when using an array:**
881+
882+
$$
883+
\boxed{
884+
\displaystyle O(|V|^2)
885+
}
886+
$$
887+
888+
When using an array, Dijkstra's algorithm must loop over **all nodes** to pick the next closest node. This is clearly a lot slower than using a [priority queue](computer-science.md#priority-queue), where that operation can be done much faster (e.g. $ O(\log |V|) $).
889+
890+
The initial naive time complexity is:
891+
892+
$$
893+
O(|V|^2 + |E|)
894+
$$
895+
896+
- The $ O(|V|^2) $ comes from scanning all $ |V| $ nodes every time we select the next node — this happens $ |V| $ times.
897+
- The $ O(|E|) $ comes from relaxing edges, which happens once per edge over the whole run.
898+
899+
In asymptotic analysis, we drop lower-order terms. Since even in the worst case $ |E| \le |V|^2 $, we simplify:
900+
901+
$$
902+
O(|V|^2 + |E|) = O(|V|^2)
903+
$$
904+
905+
As a matter of fact, for [simple](#simple-graph) [connected](#connected-graph) graphs the boundary of $|E|$ proves[^edge-boundaries] that inequality.
906+
907+
You don't need to remember all the maths — just remember that when using an **array**, Dijkstra runs in **$ O(|V|^2) $** time.
908+
909+
[^edge-boundaries]: The minimum bound are [trees](#trees) and the maximum bound are [complete graphs](#complete-graphs) which are noted in the [simple graph section](#simple-graph)
910+
911+
---
866912

867913
- Finds shortest path from starting node, to any other location, not just the desired location.
868914
- Works on weighted, weighted graphs and weighted digraphs. **Where no negative weight cycles exist**
@@ -871,7 +917,7 @@ $$\displaystyle O(|V^2|)$$
871917

872918
Pseudocode
873919

874-
```js
920+
```js title="Dijkstras with a priority queue"
875921
Algorithm Dijkstra(Graph, source):
876922
// initialise the algorithm
877923
for each vertex V in Graph G=(V,E) do
@@ -880,7 +926,7 @@ for each vertex V in Graph G=(V,E) do
880926
add V to unexplored // Unexplored nodes
881927
End do
882928

883-
dist[source] :=0 // Distance from source to source
929+
dist[source] := 0 // Distance from source to source
884930

885931
while unexplored is not empty do
886932
V := vertex in unexplored with minimum dist[V] // Greedy Priority Queue (1)
@@ -896,7 +942,7 @@ while unexplored is not empty do
896942
End do // shortest path information in dist[], pred[]
897943
```
898944

899-
1. With Fibonacci heap, this discrete operation is `O(log |V|)`
945+
1. With Fibonacci heap, this discrete operation is `O(log |V|)`. But once again, not something you **need** to remember
900946

901947
**Limitations**
902948

0 commit comments

Comments
 (0)