Union-find structure

This commit is contained in:
Antti H S Laaksonen 2017-01-08 14:45:46 +02:00
parent b0f75a819e
commit bd6525b526
1 changed files with 87 additions and 111 deletions

View File

@ -394,35 +394,29 @@ called for each edge in the graph.
We will solve the problem using a union-find structure We will solve the problem using a union-find structure
that implements both the functions in $O(\log n)$ time. that implements both the functions in $O(\log n)$ time.
Thus, the time complexity of Kruskal's algorithm Thus, the time complexity of Kruskal's algorithm
will be only $O(m \log n)$ after sorting the edge list. will be $O(m \log n)$ after sorting the edge list.
\section{Union-find-rakenne} \section{Union-find structure}
\index{union-find-rakenne} \index{union-find structure}
\key{Union-find-rakenne} pitää yllä The \key{union-find structure} maintains
alkiojoukkoja. a collection of sets.
Joukot ovat erillisiä, The sets are disjoint, so no element
eli tietty alkio on tarkalleen belongs to more than one set.
yhdessä joukossa. Two $O(\log n)$ time operations are supported.
Rakenne tarjoaa kaksi operaatiota, The first operation checks if two elements
jotka toimivat ajassa $O(\log n)$. belong to the same set,
Ensimmäinen operaatio tarkistaa, and the second operation joins two sets into a single set.
ovatko kaksi alkiota samassa joukossa.
Toinen operaatio yhdistää kaksi
joukkoa toisiinsa.
\subsubsection{Rakenne} \subsubsection{Structure}
Union-find-rakenteessa jokaisella In the union-find structure, one element in each set
joukolla on edustaja-alkio. is the representative of the set.
Kaikki muut joukon alkiot osoittavat All other elements in the set point to the
edustajaan joko suoraan tai representative directly or through other elements in the set.
muiden alkioiden kautta. For example, in the following picture there are three sets:
$\{1,4,7\}$, $\{5\}$ and $\{2,3,6,8\}$.
Esimerkiksi jos joukot ovat
$\{1,4,7\}$, $\{5\}$ ja $\{2,3,6,8\}$,
tilanne voisi olla:
\begin{center} \begin{center}
\begin{tikzpicture} \begin{tikzpicture}
\node[draw, circle] (1) at (0,-1) {$1$}; \node[draw, circle] (1) at (0,-1) {$1$};
@ -443,26 +437,23 @@ tilanne voisi olla:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Tässä tapauksessa alkiot 4, 5 ja 2 In this case the representatives
ovat joukkojen edustajat. of the sets are 4, 5 and 2.
Minkä tahansa alkion edustaja For each element, we can find the representative
löytyy kulkemalla alkiosta lähtevää polkua for the corresponding set by following the
eteenpäin niin kauan, kunnes polku päättyy. path that begins at the element.
Esimerkiksi alkion 6 edustaja on 2, For example, element 2 is the representative for the set
koska alkiosta 6 lähtevä that contains element 6 because
polku on $6 \rightarrow 3 \rightarrow 2$. the path is $6 \rightarrow 3 \rightarrow 2$.
Tämän avulla voi selvittää, Thus, two elements belong to the same set exactly when
ovatko kaksi alkiota samassa joukossa: they point to the same representative.
jos kummankin alkion edustaja on sama,
alkiot ovat samassa joukossa,
ja muuten ne ovat eri joukoissa.
Kahden joukon yhdistäminen tapahtuu Two sets can be combined by connecting the
valitsemalla toinen edustaja representative of one set to the
joukkojen yhteiseksi edustajaksi representative of another set.
ja kytkemällä toinen edustaja siihen. For example, sets
Esimerkiksi joukot $\{1,4,7\}$ ja $\{2,3,6,8\}$ $\{1,4,7\}$ and $\{2,3,6,8\}$
voi yhdistää näin joukoksi $\{1,2,3,4,6,7,8\}$: can be combined as follows into set $\{1,2,3,4,6,7,8\}$:
\begin{center} \begin{center}
\begin{tikzpicture} \begin{tikzpicture}
\node[draw, circle] (1) at (2,-1) {$1$}; \node[draw, circle] (1) at (2,-1) {$1$};
@ -484,73 +475,75 @@ voi yhdistää näin joukoksi $\{1,2,3,4,6,7,8\}$:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Joukkojen yhteiseksi edustajaksi valitaan alkio 2, In this case, element 2 becomes the representative
minkä vuoksi alkio 4 yhdistetään siihen. for the whole set and the old representative 4
Tästä lähtien alkio 2 edustaa kaikkia joukon alkioita. points to it.
Tehokkuuden kannalta oleellista on, The efficiency of the operations depends on
miten yhdistäminen tapahtuu. the way the sets are combined.
Osoittautuu, että ratkaisu on yksinkertainen: It turns out that we can follow a simple strategy
riittää yhdistää aina pienempi joukko suurempaan, and always connect the representative of the
tai kummin päin tahansa, smaller set to the representative of the larger set
jos joukot ovat yhtä suuret. (or, if the sets are of the same size,
Tällöin pisin ketju both choices are fine).
alkiosta edustajaan on aina luokkaa $O(\log n)$, Using this strategy, the length of a path from
koska jokainen askel eteenpäin a element in a set to a representative is
ketjussa kaksinkertaistaa always $O(\log n)$ because each step forward
vastaavan joukon koon. in the path doubles the size of the corresponding set.
\subsubsection{Toteutus} \subsubsection{Implementation}
Union-find-rakenne on kätevää toteuttaa We can implement the union-find structure
taulukoiden avulla. using arrays.
Seuraavassa toteutuksessa taulukko \texttt{k} In the following implementation,
viittaa seuraavaan alkioon ketjussa array \texttt{k} contains for each element
tai alkioon itseensä, jos alkio on edustaja. the next element
Taulukko \texttt{s} taas kertoo jokaiselle edustajalle, in the path, or the element itself if it is
kuinka monta alkiota niiden joukossa on. a representative,
and array \texttt{s} indicates for each representative
Aluksi jokainen alkio on omassa joukossaan, the size of the corresponding set.
jonka koko on 1:
Initially, each element has an own set with size 1:
\begin{lstlisting} \begin{lstlisting}
for (int i = 1; i <= n; i++) k[i] = i; for (int i = 1; i <= n; i++) k[i] = i;
for (int i = 1; i <= n; i++) s[i] = 1; for (int i = 1; i <= n; i++) s[i] = 1;
\end{lstlisting} \end{lstlisting}
Funktio \texttt{id} kertoo alkion $x$ The function \texttt{find} returns
joukon edustajan. Alkion edustaja löytyy the representative for element $x$.
käymällä ketju läpi alkiosta $x$ alkaen. The representative can be found by following
the path that begins at element $x$.
\begin{lstlisting} \begin{lstlisting}
int id(int x) { int find(int x) {
while (x != k[x]) x = k[x]; while (x != k[x]) x = k[x];
return x; return x;
} }
\end{lstlisting} \end{lstlisting}
Funktio \texttt{sama} kertoo, The function \texttt{same} finds out
ovatko alkiot $a$ ja $b$ samassa joukossa. whether elements $a$ and $b$ belong to the same set.
Tämä onnistuu helposti funktion This can easily be done by using the
\texttt{id} avulla. function \texttt{find}.
\begin{lstlisting} \begin{lstlisting}
bool sama(int a, int b) { bool same(int a, int b) {
return id(a) == id(b); return find(a) == find(b);
} }
\end{lstlisting} \end{lstlisting}
\begin{samepage} \begin{samepage}
Funktio \texttt{liita} yhdistää The function \texttt{union} combines the sets
puolestaan alkioiden $a$ ja $b$ osoittamat that contain elements $a$ and $b$
joukot yhdeksi joukoksi. into a single set.
Funktio etsii ensin joukkojen edustajat The function first finds the representatives
ja yhdistää sitten pienemmän joukon suurempaan. of the sets and then connects the smaller
set to the larger set.
\begin{lstlisting} \begin{lstlisting}
void liita(int a, int b) { void union(int a, int b) {
a = id(a); a = find(a);
b = id(b); b = find(b);
if (s[b] > s[a]) swap(a,b); if (s[b] > s[a]) swap(a,b);
s[a] += s[b]; s[a] += s[b];
k[b] = a; k[b] = a;
@ -558,31 +551,14 @@ void liita(int a, int b) {
\end{lstlisting} \end{lstlisting}
\end{samepage} \end{samepage}
Funktion \texttt{id} aikavaativuus on $O(\log n)$ The time complexity of the function \texttt{find}
olettaen, että ketjun pituus on luokkaa $O(\log n)$. is $O(\log n)$ assuming that the length of the
Niinpä myös funktioiden \texttt{sama} ja \texttt{liita} path is $O(\log n)$.
aikavaativuus on $O(\log n)$. Thus, the functions \texttt{same} and \texttt{union}
Funktio \texttt{liita} varmistaa, also work in $O(\log n)$ time.
että ketjun pituus on luokkaa $O(\log n)$ The function \texttt{union} ensures that the
yhdistämällä pienemmän joukon suurempaan. length of each path is $O(\log n)$ by connecting
the smaller set to the larger set.
% Funktiota \texttt{id} on mahdollista vielä tehostaa
% seuraavasti:
%
% \begin{lstlisting}
% int id(int x) {
% if (x == k[x]) return x;
% return k[x] = id(x);
% }
% \end{lstlisting}
%
% Nyt joukon edustajan etsimisen yhteydessä kaikki ketjun
% alkiot laitetaan osoittamaan suoraan edustajaan.
% On mahdollista osoittaa, että tämän avulla
% funktioiden \texttt{sama} ja \texttt{liita}
% aikavaativuus on tasoitetusti
% vain $O(\alpha(n))$, missä $\alpha(n)$ on
% hyvin hitaasti kasvava käänteinen Ackermannin funktio.
\section{Primin algoritmi} \section{Primin algoritmi}