Dijkstra's algorithm

This commit is contained in:
Antti H S Laaksonen 2017-01-07 20:36:06 +02:00
parent d4dd36b4f4
commit 11e33b0eba
1 changed files with 91 additions and 107 deletions

View File

@ -325,36 +325,32 @@ $O(nm)$ and it is possible to create inputs
that make the algorithm as slow as the that make the algorithm as slow as the
standard BellmanFord algorithm. standard BellmanFord algorithm.
\section{Dijkstran algoritmi} \section{Dijkstra's algorithm}
\index{Dijkstran algoritmi@Dijkstran algoritmi} \index{Dijkstra's algorithm}
\key{Dijkstran algoritmi} etsii BellmanFordin \key{Dijkstra's algorithm} finds the shortest
algoritmin tavoin lyhimmät polut paths from the starting node to all other nodes,
alkusolmusta kaikkiin muihin solmuihin. like the BellmanFord algorithm.
Dijkstran algoritmi on tehokkaampi kuin The benefit in Dijsktra's algorithm is that
BellmanFordin algoritmi, it is more efficient and can be used for
minkä ansiosta se soveltuu suurten processing large graphs.
verkkojen käsittelyyn. However, the algorithm requires that there
Algoritmi vaatii kuitenkin, are no negative weight edges in the graph.
ettei verkossa ole negatiivisia kaaria.
Dijkstran algoritmi vastaa Like the BellmanFord algorithm,
BellmanFordin algoritmia siinä, Dijkstra's algorithm maintains estimated distances
että se pitää for the nodes and improves them during the algorithm.
yllä etäisyysarvioita solmuihin Dijkstra's algorithm is efficient because
ja parantaa niitä algoritmin aikana. it only processes
Algoritmin tehokkuus perustuu each edge in the graph once, using the fact
siihen, että sen riittää käydä läpi that there are no negative edges.
verkon kaaret vain kerran
hyödyntäen tietoa,
ettei verkossa ole negatiivisia kaaria.
\subsubsection{Esimerkki} \subsubsection{Example}
Tarkastellaan Dijkstran algoritmin toimintaa Let's consider how Dijkstra's algorithm
seuraavassa verkossa, kun alkusolmuna works in the following graph when the
on solmu 1: starting node is node 1:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.9] \begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (1,3) {3}; \node[draw, circle] (1) at (1,3) {3};
@ -377,25 +373,18 @@ on solmu 1:
\path[draw,thick,-] (4) -- node[font=\small,label=below:1] {} (5); \path[draw,thick,-] (4) -- node[font=\small,label=below:1] {} (5);
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
BellmanFordin algoritmin tavoin Like in the BellmanFord algorithm,
alkusolmun etäisyysarvio on 0 the estimated distance is 0 to the starting node
ja kaikissa muissa solmuissa etäisyysarvio and infinite to all other nodes.
on aluksi ääretön.
Dijkstran algoritmi At each step, Dijkstra's algorithm selects a node
ottaa joka askeleella käsittelyyn that has not been processed yet and whose estimated distance
sellaisen solmun, is as small as possible.
jota ei ole vielä käsitelty The first such node is node 1 with distance 0.
ja jonka etäisyysarvio on
mahdollisimman pieni.
Alussa tällainen solmu on solmu 1,
jonka etäisyysarvio on 0.
Kun solmu tulee käsittelyyn, When a node is selected, the algorithm
algoritmi käy läpi kaikki goes through all edges that begin from the node
siitä lähtevät kaaret ja and improves the distances using them:
parantaa etäisyysarvioita
niiden avulla:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.9] \begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (1,3) {3}; \node[draw, circle] (1) at (1,3) {3};
@ -422,12 +411,10 @@ niiden avulla:
\path[draw=red,thick,->,line width=2pt] (4) -- (5); \path[draw=red,thick,->,line width=2pt] (4) -- (5);
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Solmun 1 käsittely paransi etäisyysarvioita The edges from node 1 improved distances to
solmuihin 2, 4 ja 5, nodes 2, 4 and 5 whose now distances are now 5, 9 and 1.
joiden uudet etäisyydet ovat nyt 5, 9 ja 1.
Seuraavaksi käsittelyyn tulee solmu 5, The next node to be processed is node 5 with distance 1:
jonka etäisyys on 1:
\begin{center} \begin{center}
\begin{tikzpicture} \begin{tikzpicture}
\node[draw, circle] (1) at (1,3) {3}; \node[draw, circle] (1) at (1,3) {3};
@ -452,7 +439,7 @@ jonka etäisyys on 1:
\path[draw=red,thick,->,line width=2pt] (5) -- (2); \path[draw=red,thick,->,line width=2pt] (5) -- (2);
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Tämän jälkeen vuorossa on solmu 4: After this, the next node is node 4:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.9] \begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (1,3) {3}; \node[draw, circle] (1) at (1,3) {3};
@ -478,17 +465,14 @@ Tämän jälkeen vuorossa on solmu 4:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Dijkstran algoritmissa on hienoutena, A nice property in Dijkstra's algorithm is that
että aina kun solmu tulee käsittelyyn, whenever a node is selected, its distance is final.
sen etäisyysarvio on siitä lähtien lopullinen. For example, at this point of the algorithm,
Esimerkiksi tässä vaiheessa the distances 0, 1 and 3 are the final distances
etäisyydet 0, 1 ja 3 ovat lopulliset to nodes 1, 5 and 4.
etäisyydet solmuihin 1, 5 ja 4.
Algoritmi käsittelee vastaavasti After this, the algorithm processes the two
vielä kaksi viimeistä solmua, remaining nodes, and the final distances are as follows:
minkä jälkeen algoritmin päätteeksi
etäisyydet ovat:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.9] \begin{tikzpicture}[scale=0.9]
@ -513,13 +497,14 @@ etäisyydet ovat:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
\subsubsection{Negatiiviset kaaret} \subsubsection{Negative edges}
Dijkstran algoritmin tehokkuus perustuu siihen, The efficiency of Dijkstra's algorithm is
että verkossa ei ole negatiivisia kaaria. based on the fact that the graph doesn't
Jos verkossa on negatiivinen kaari, contain negative edges.
algoritmi ei välttämättä toimi oikein. If there is a negative edge,
Tarkastellaan esimerkkinä seuraavaa verkkoa: the algorithm may give incorrect results.
As an example, consider the following graph:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.9] \begin{tikzpicture}[scale=0.9]
@ -535,54 +520,53 @@ Tarkastellaan esimerkkinä seuraavaa verkkoa:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
\noindent \noindent
Lyhin polku solmusta 1 solmuun 4 on The shortest path from node 1 to node 4 is
$1 \rightarrow 3 \rightarrow 4$, $1 \rightarrow 3 \rightarrow 4$,
ja sen pituus on 1. and its length is 1.
Dijkstran algoritmi löytää However, Dijkstra's algorithm
kuitenkin keveimpiä kaaria seuraten finds the path $1 \rightarrow 2 \rightarrow 4$
polun $1 \rightarrow 2 \rightarrow 4$. by following the lightest edges.
Algoritmi ei pysty ottamaan huomioon, The algorithm cannot recognize that
että alemmalla polulla kaaren paino $-5$ in the lower path, the weight $-5$
kumoaa aiemman suuren kaaren painon $6$. compensates the previous large weight $6$.
\subsubsection{Toteutus} \subsubsection{Implementation}
Seuraava Dijkstran algoritmin toteutus laskee The following implementation of Dijkstra's algorithm
pienimmän etäisyyden solmusta $x$ kaikkiin muihin solmuihin. calculates the minimum distance from a node $x$
Verkko on tallennettu taulukkoon \texttt{v} to all other nodes.
vieruslistoina, joissa on pareina kohdesolmu The graph is stored in an array \texttt{v}
ja kaaren pituus. as adjacency lists that contain target nodes
and weights for each edge.
Dijkstran algoritmin tehokas toteutus vaatii, An efficient implementation of Dijkstra's algorithm
että verkosta pystyy löytämään requires that it is possible to quickly find the
nopeasti vielä käsittelemättömän solmun, smallest node that has not been processed.
jonka etäisyysarvio on pienin. A suitable data structure for this is a priority queue
Sopiva tietorakenne tähän on prioriteettijono, that contains the nodes ordered by the estimated distances.
jossa solmut ovat järjestyksessä etäisyys\-arvioiden mukaan. Using a priority queue, the next node to be processed
Prioriteettijonon avulla can be retrieved in logarithmic time.
seuraavaksi käsiteltävän solmun saa selville logaritmisessa ajassa.
Seuraavassa toteutuksessa prioriteettijono sisältää In the following implementation,
pareja, joiden ensimmäinen kenttä on etäisyysarvio the priority queue contains pairs whose first
ja toinen kenttä on solmun tunniste: element is the estimated distance and second
element is the identifier of the corresponding node.
\begin{lstlisting} \begin{lstlisting}
priority_queue<pair<int,int>> q; priority_queue<pair<int,int>> q;
\end{lstlisting} \end{lstlisting}
Pieni hankaluus on, A small difficulty is that in Dijkstra's algorithm,
että Dijkstran algoritmissa täytyy saada selville we should find the node with \emph{minimum} distance,
\emph{pienimmän} etäisyysarvion solmu, while the C++ priority queue finds the \emph{maximum}
kun taas C++:n prioriteettijono antaa oletuksena element as default.
\emph{suurimman} alkion. An easy solution is to use \emph{negative} distances,
Helppo ratkaisu on tallentaa etäisyysarviot so we can directly use the C++ priority queue.
\emph{negatiivisina}, jolloin C++:n prioriteettijonoa
voi käyttää suoraan.
Koodi merkitsee taulukkoon \texttt{z}, The code keeps track of processed nodes
onko solmu käsitelty, in array \texttt{z},
ja pitää yllä etäisyysarvioita taulukossa \texttt{e}. and maintains estimated distances in array \texttt{e}.
Alussa alkusolmun etäisyysarvio on 0 Initially, the distance to the starting node is 0,
ja jokaisen muun solmun etäisyysarviona and the distance to all other nodes is $10^9$
on ääretöntä vastaava $10^9$. that corresponds to infinity.
\begin{lstlisting} \begin{lstlisting}
for (int i = 1; i <= n; i++) e[i] = 1e9; for (int i = 1; i <= n; i++) e[i] = 1e9;
@ -601,10 +585,10 @@ while (!q.empty()) {
} }
\end{lstlisting} \end{lstlisting}
Yllä olevan toteutuksen aikavaativuus on $O(n+m \log m)$, The time complexity of the above implementation is
koska algoritmi käy läpi kaikki verkon solmut $O(n+m \log m)$ because the algorithm goes through
ja lisää jokaista kaarta kohden korkeintaan all nodes in the graph, and adds for each edge
yhden etäisyysarvion prioriteettijonoon. at most one estimated distance to the priority queue.
\section{FloydWarshallin algoritmi} \section{FloydWarshallin algoritmi}