Na čo to je?

Euklidov algoritmus je jeden z najstarších algoritmov na svete. Slúži na nájdenie najväčšieho spoločného deliteľa dvoch čísel. V skratke, majme dve kladné čísla $a$ a $b$. Najväčší spoločný deliteľ týchto dvoch čísel je také $x$ pre ktoré platí, že $x$ delí $a$, $x$ delí $b$ a zároveň je to najväčšie $x$ pre ktoré toto platí.

Uvedieme si pár príkladov, pre $a$, $b$ a $x$:

$a=14$, $b=21$, $x=7$

$a = 18$, $b = 7$, $x=1$

Ako to funguje?

Predstavme si dve kladné celé čísla $a$ a $b$. Predpokladajme nachvíľu, že $a>b$. Dôležitým pozorovaním je, že pokiaľ nejaké $x$ delí $a$ aj $b$, tak určite delí aj $a-b$.

Zdôvodnenie je jednoduché, kedže $a = k\cdot x$ a $b = l\cdot x$ tak $a-b = (k-l)\cdot x$ teda $a-b$ je celočíselným násobkom $x$ a teda inak povedané -- deliteľné $x$.

Ak sa zamyslíte je pre nás už jednoduché nájsť spoločného deliteľa dvoch čísel $a$ a $b$. Algoritmus by mohol vyzerať takto:

int najdi(int a, int b)
{
    if(a<b) return najdi(b, a);

    if(b == 0) return a;
    else return najdi(a-b, b);
}

Čo v rekurzívnej funkcii robíme? Pomocou nášho jediného pozorovania počítame najväčší spoločný deliteľ. Ako? Majme dve čísla, najprv sa uistíme, že prvé číslo je väčšie rovné ako druhé. Pokiaľ je menšie z nich $0$, tak vrátime to druhé nakoľko, nulu delí všetko a najväčšie kladné číslo, ktoré delí $a$ je práve $a$. Pokiaľ ale druhé z týchto čísiel nie je 0, vieme použiť naše pozorovanie. Pokiaľ si najväčší spoločný deliteľ $a$ a $b$ označíme $x$, tak toto $x$ je aj najväčší spoločný deliteľ čísel $a-b$ a $b$. Prečo?

To, že delí $b$ je zrejmé a deliteľnosť $a-b$ týmto číslom sme si už skôr dokázali. Zároveň nemôže existovať väčšie číslo $y(y>x)$, ktoré by delilo aj $a-b$ a $b$ lebo by delilo aj $a$ a teda $x$ by nebolo najväčší spoločný deliteľ $a$ a $b$.

Z tohto teda vyplýva, že nám na nájdenie najväčšieho spoločného deliteľa $a$ a $b$ stačí nájsť najväčší spoločný deliteľ čísel $a-b$ a $b$. Toto nám ale zaručí, že čísla, ktorých najväčší spoločný deliteľ postupne hľadáme klesajú a teda sa dopracujeme k tomu, že jedno z nich je 0.

Kam s tým?

Toto bola ilustrácia myšlienky, na ktorej je postavený Euklidov algoritmus. Samotný algoritmus už je iba zrýchlením daného výpočtu. Kde je problém?

Problém je v tom, pokiaľ je $a$, teda väčšie z čísel veľmi veľké a druhé číslo veľmi malé. Čo sa vtedy stane, nech $a=100$ a $b = 8$. Naša funkcia najdi sa bude postupne volať s parametrami $(100, 8)$, $(92, 8)$, $(84, 8)$, $(76, 8)$ ... $(12, 8)$, $(4, 8)$, $(8, 4)$, $(4, 4)$, $(4, 0)$. Vidíme, že výsledkom je $4$. Čo je problém je dlhá postupnosť volaní funkcie, kedy sa nerobilo nič iné ako odčítavanie toho istého jedného čísla od druhého. Ako sa vieme tomuto vyhnúť? Všimnite si, že v momente kedy máme dve čísla $a$ a $b$ tak sa neudeje nič iné ako odčítavanie $b$ od $a$ pokým $a$ neklesne veľkosťou pod $b$. Snáď by sa dalo zistiť, na akom čísle zastaneme. Hľadáme teda číslo, ktoré dostaneme odčítavaním $b$ od $a$ pokým $a$ neklesne prvý krát pod $b$. Uvedomme si, že toto číslo je práve $a%b$ teda zvyšok $a$ po delení $b$. Zvyšok $a$ po delení $b$ je totiž práve tá -- časť -- $a$, ktorú už nevieme akoby v delení zobrať $b$-čkom z $a$.

Finálna implementácia sa teda od predchádzajúcej nebude veľmi líšiť a môže vyzerať napr. takto:

int najdi(int a, int b)
{
    if(a<b) return najdi(b, a);

    if(b == 0) return a;
    else return najdi(b, a%b);
}

Čas poslednej úpravy: 5. august 2019 19:54