Chapter 3 first version

This commit is contained in:
Antti H S Laaksonen 2016-12-31 13:19:22 +02:00
parent 9fd1b20e8e
commit 5cf7cf710b
1 changed files with 113 additions and 116 deletions

View File

@ -768,118 +768,121 @@ sort(v.begin(), v.end(), cmp);
\index{binary search} \index{binary search}
Tavallinen tapa etsiä alkiota taulukosta A general method for searching for an element
on käyttää \texttt{for}-silmukkaa, joka käy läpi in an array is to use a \texttt{for} loop
taulukon sisällön alusta loppuun. that iterates through all elements in the array.
Esimerkiksi seuraava koodi etsii alkiota For example, the following code searches for
$x$ taulukosta \texttt{t}. an element $x$ in array \texttt{t}:
\begin{lstlisting} \begin{lstlisting}
for (int i = 1; i <= n; i++) { for (int i = 1; i <= n; i++) {
if (t[i] == x) // alkio x löytyi kohdasta i if (t[i] == x) // x found at index i
} }
\end{lstlisting} \end{lstlisting}
Tämän menetelmän aikavaativuus on $O(n)$, The time complexity of this approach is $O(n)$
koska pahimmassa tapauksessa koko taulukko täytyy because in the worst case, we have to check
käydä läpi. all elements in the array.
Jos taulukon sisältö voi olla mikä tahansa, If the array can contain any elements,
tämä on kuitenkin tehokkain mahdollinen menetelmä, this is also the best possible approach because
koska saatavilla ei ole lisätietoa siitä, there is no additional information available where
mistä päin taulukkoa alkiota $x$ kannattaa etsiä. in the array we should search for the element $x$.
Tilanne on toinen silloin, kun taulukko on However, if the array is \emph{sorted},
järjestyksessä. the situation is different.
Tässä tapauksessa haku on mahdollista toteuttaa In this case it is possible to perform the
paljon nopeammin, koska taulukon järjestys search much faster, because the order of the
ohjaa etsimään alkiota oikeasta suunnasta. elements in the array guides us.
Seuraavaksi käsiteltävä \key{binäärihaku} The following \key{binary search} algorithm
löytää alkion järjestetystä taulukosta efficiently searches for an element in a sorted array
tehokkaasti ajassa $O(\log n)$. in $O(\log n)$ time.
\subsubsection{Toteutus 1} \subsubsection{Method 1}
Perinteinen tapa toteuttaa binäärihaku muistuttaa sanan etsimistä The traditional way to implement binary search
sanakirjasta. Haku puolittaa joka askeleella hakualueen taulukossa, resembles looking for a word in a dictionary.
kunnes lopulta etsittävä alkio löytyy tai osoittautuu, At each step, the search halves the active region in the array,
että sitä ei ole taulukossa. until the desired element is found, or it turns out
that there is no such element.
Haku tarkistaa ensin taulukon keskimmäisen alkion. First, the search checks the middle element in the array.
Jos keskimmäinen alkio on etsittävä alkio, haku päättyy. If the middle element is the desired element,
Muuten haku jatkuu taulukon vasempaan tai oikeaan osaan sen mukaan, the search terminates.
onko keskimmäinen alkio suurempi vain pienempi kuin etsittävä alkio. Otherwise, the search recursively continues
to the left half or to the right half of the array,
depending on the value of the middle element.
Yllä olevan idean voi toteuttaa seuraavasti: The above idea can be implemented as follows:
\begin{lstlisting} \begin{lstlisting}
int a = 1, b = n; int a = 1, b = n;
while (a <= b) { while (a <= b) {
int k = (a+b)/2; int k = (a+b)/2;
if (t[k] == x) // alkio x löytyi kohdasta k if (t[k] == x) // x found at index k
if (t[k] > x) b = k-1; if (t[k] > x) b = k-1;
else a = k+1; else a = k+1;
} }
\end{lstlisting} \end{lstlisting}
Algoritmi pitää yllä väliä $a \ldots b$, joka on The algorithm maintains a range $a \ldots b$
jäljellä oleva hakualue taulukossa. that corresponds to the active region in the array.
Aluksi väli on $1 \ldots n$ eli koko taulukko. Initially, the range is $1 \ldots n$, the whole array.
Välin koko puolittuu algoritmin joka vaiheessa, The algorithm halves the size of the range at each step,
joten aikavaativuus on $O(\log n)$. so the time complexity is $O(\log n)$.
\subsubsection{Toteutus 2} \subsubsection{Method 2}
Vaihtoehtoinen tapa toteuttaa binäärihaku An alternative method for implementing binary search
perustuu taulukon tehostettuun läpikäyntiin. is based on a more efficient way to iterate through
Ideana on käydä taulukkoa läpi hyppien the elements in the array.
ja hidastaa vauhtia, kun etsittävä alkio lähestyy. The idea is to make jumps and slow the speed
when we get closer to the desired element.
Haku käy taulukkoa läpi vasemmalta oikealle aloittaen The search goes through the array from the left to
hypyn pituudesta $n/2$. the right, and the initial jump length is $n/2$.
Joka vaiheessa hypyn pituus puolittuu: At each step, the jump length will be halved:
ensin $n/4$, sitten $n/8$, sitten $n/16$ jne., first $n/4$, then $n/8$, $n/16$, etc., until
kunnes lopulta hypyn pituus on 1. finally the length is 1.
Hyppyjen jälkeen joko haettava alkio on löytynyt After the jumps, either the desired element has
tai selviää, että sitä ei ole taulukossa. been found or we know that it doesn't exist in the array.
Seuraava koodi toteuttaa äskeisen idean: The following code implements the above idea:
\begin{lstlisting} \begin{lstlisting}
int k = 1; int k = 1;
for (int b = n/2; b >= 1; b /= 2) { for (int b = n/2; b >= 1; b /= 2) {
while (k+b <= n && t[k+b] <= x) k += b; while (k+b <= n && t[k+b] <= x) k += b;
} }
if (t[k] == x) // alkio x löytyi kohdasta k if (t[k] == x) // x was found at index k
\end{lstlisting} \end{lstlisting}
Muuttuja $k$ on läpikäynnin kohta taulukossa Variable $k$ is the position in the array,
ja muuttuja $b$ on hypyn pituus. and variable $b$ is the jump length.
Jos alkio $x$ esiintyy taulukossa, If the array contains the element $x$,
sen kohta on muuttujassa $k$ algoritmin päätteeksi. the index of the element will be in variable $k$
Algoritmin aikavaativuus on $O(\log n)$, after the search.
koska \texttt{while}-silmukassa oleva koodi suoritetaan The time complexity of the algorithm is $O(\log n)$,
aina enintään kahdesti. because the code in the \texttt{while} loop
is performed at most twice for each jump length.
\subsubsection{Muutoskohdan etsiminen} \subsubsection{Finding the smallest solution}
Käytännössä binäärihakua tarvitsee toteuttaa In practice, it is seldom needed to implement
harvoin alkion etsimiseen taulukosta, binary search for array search,
koska sen sijasta voi käyttää standardikirjastoa. because we can use the standard library instead.
Esimerkiksi C++:n funktiot \texttt{lower\_bound} For example, the C++ functions \texttt{lower\_bound}
ja \texttt{upper\_bound} toteuttavat binäärihaun and \texttt{upper\_bound} implement binary search,
ja tietorakenne \texttt{set} ylläpitää joukkoa, and the data structure \texttt{set} maintains a
jonka operaatiot ovat $O(\log n)$-aikaisia. set of elements with $O(\log n)$ time operations.
Sitäkin tärkeämpi binäärihaun käyttökohde on However, an important use for binary search is
funktion \key{muutoskohdan} etsiminen. to find a position where the value of a function changes.
Oletetaan, että haluamme löytää pienimmän arvon $k$, Suppose that we wish to find the smallest value $k$
joka on kelvollinen ratkaisu ongelmaan. that is a valid solution for a problem.
Käytössämme on funktio $\texttt{ok}(x)$, We are given a function $\texttt{ok}(x)$
joka palauttaa \texttt{true}, jos $x$ on kelvollinen that returns \texttt{true} if $x$ is a valid solution
ratkaisu, ja muuten \texttt{false}. and \texttt{false} otherwise.
Lisäksi tiedämme, että $\texttt{ok}(x)$ on \texttt{false} In addition, we know that $\texttt{ok}(x)$ is \texttt{false}
aina kun $x<k$ ja \texttt{true} aina kun $x \geq k$. when $x<k$ and \texttt{true} when $x \ge k$.
% Toisin sanoen haluamme löytää funktion \texttt{ok} \emph{muutoskohdan}, The situation looks as follows:
% jossa arvosta \texttt{false} tulee arvo \texttt{true}.
Tilanne näyttää seuraavalta:
\begin{center} \begin{center}
\begin{tabular}{r|rrrrrrrr} \begin{tabular}{r|rrrrrrrr}
@ -891,8 +894,7 @@ $\texttt{ok}(x)$ & \texttt{false} & \texttt{false}
\end{center} \end{center}
\noindent \noindent
Nyt muutoskohta on mahdollista etsiä käyttämällä The value $k$ can be found using binary search:
binäärihakua:
\begin{lstlisting} \begin{lstlisting}
int x = -1; int x = -1;
@ -902,43 +904,41 @@ for (int b = z; b >= 1; b /= 2) {
int k = x+1; int k = x+1;
\end{lstlisting} \end{lstlisting}
Haku etsii suurimman $x$:n arvon, The search finds the largest value of $x$ for which
jolla $\texttt{ok}(x)$ on \texttt{false}. $\texttt{ok}(x)$ is \texttt{false}.
Niinpä tästä seuraava arvo $k=x+1$ Thus, the next value $k=x+1$
on pienin arvo, jolla $\texttt{ok}(k)$ on \texttt{true}. is the smallest possible value for which
Hypyn aloituspituus $z$ tulee olla $\texttt{ok}(k)$ is \texttt{true}.
sopiva suuri luku, esimerkiksi sellainen, The initial jump length $z$ has to be
jolla $\texttt{ok}(z)$ on varmasti \texttt{true}. large enough, for example some value
for which we know beforehand that $\texttt{ok}(z)$ is \texttt{true}.
Algoritmi kutsuu $O(\log z)$ kertaa funktiota The algorithm calls the function \texttt{ok}
\texttt{ok}, joten kokonaisaikavaativuus $O(\log z)$ times, so the total time complexity
riippuu siitä, kauanko funktion \texttt{ok} depends on the function \texttt{ok}.
suoritus kestää. For example, if the function works in $O(n)$ time,
Esimerkiksi jos ratkaisun tarkastus the total time complexity becomes $O(n \log z)$.
vie aikaa $O(n)$, niin kokonaisaikavaativuus
on $O(n \log z)$.
\subsubsection{Huippuarvon etsiminen} \subsubsection{Finding the maximum value}
Binäärihaulla voi myös etsiä Binary search can also be used for finding
suurimman arvon funktiolle, the maximum value for a function that is
joka on ensin kasvava ja sitten laskeva. first increasing and then decreasing.
Toisin sanoen tehtävänä on etsiä arvo Our task is to find a value $k$ such that
$k$ niin, että
\begin{itemize} \begin{itemize}
\item \item
$f(x)<f(x+1)$, kun $x<k$, ja $f(x)<f(x+1)$ when $x<k$, and
\item \item
$f(x)>f(x+1)$, kun $x >= k$. $f(x)>f(x+1)$ when $x >= k$.
\end{itemize} \end{itemize}
Ideana on etsiä binäärihaulla The idea is to use binary search
viimeinen kohta $x$, for finding the largest value of $x$
jossa pätee $f(x)<f(x+1)$. for which $f(x)<f(x+1)$.
Tällöin $k=x+1$, This implies that $k=x+1$
koska pätee $f(x+1)>f(x+2)$. because $f(x+1)>f(x+2)$.
Seuraava koodi toteuttaa haun: The following code implements the search:
\begin{lstlisting} \begin{lstlisting}
int x = -1; int x = -1;
@ -948,11 +948,8 @@ for (int b = z; b >= 1; b /= 2) {
int k = x+1; int k = x+1;
\end{lstlisting} \end{lstlisting}
Huomaa, että toisin kuin tavallisessa binäärihaussa, Note that unlike in the regular binary search,
tässä ei ole sallittua, here it is not allowed that successive values
että peräkkäiset arvot olisivat yhtä suuria. of the function are equal.
Silloin ei olisi mahdollista tietää, In this case it would not be possible to know
mihin suuntaan hakua tulee jatkaa. how to continue the search.