Skip to content

2 • Algoritmus

Algoritmus, vlastnosti, zápis, algoritmická složitost


Co je algoritmus

Algoritmus je konečná posloupnost přesně definovaných kroků (instrukcí), které vedou k vyřešení určitého problému. Popisuje postup tak, aby ho mohl provést člověk i počítač, nezávisle na konkrétním programovacím jazyce.

Historie pojmu

Slovo "algoritmus" pochází z přepisu jména perského matematika al-Chvárizmí (cca 780–850 n. l.), který napsal knihu o aritmetických postupech. Z arabského "al-Khwarizmi" se latinizací stal "Algorismi", a odtud dnešní "algoritmus".

Moderní teorii algoritmů formalizoval ve 20. století Alan Turing (Turingův stroj) a později Donald Knuth ve své monumentální sérii The Art of Computer Programming.

Algoritmus ≠ program

AlgoritmusProgram
Co jeAbstraktní postupKonkrétní implementace
FormaPseudokód, diagram, slovaZdrojový kód v jazyce
Závisí naLogice problémuJazyce, prostředí, knihovnách
Příklad"Najdi nejmenší prvek pole"Math.min(...arr) v JavaScriptu

Algoritmus je něco jako recept: program je konkrétní vaření podle něj.

Algoritmus ≠ heuristika

AlgoritmusHeuristika
GaranceVrátí správný výsledekPravděpodobně blízko správného
PoužitíKdyž máš čas a chceš přesnostKdyž potřebuješ rychlost
PříkladDijkstra: nejkratší cestaA*: rychlá ale ne vždy optimální

Vlastnosti algoritmu

Klasické vlastnosti, kterými musí každý algoritmus splňovat (7):

VlastnostPopis
Konečnost (finitnost)Musí skončit po konečném počtu kroků. Nesmí běžet věčně.
Resultativnost (výslednost)Musí vrátit výsledek, nebo oznámit, že řešení neexistuje.
Jednoznačnost (determinismus)Každý krok je přesně definován. Stejný vstup = stejný výstup.
VstupnostMá jasně definované vstupy, žádné skryté/externí proměnné.
ObecnostŘeší celou třídu problémů, ne jen jeden konkrétní případ.
SprávnostProkazatelně dává správný výsledek pro všechny vstupy.
EfektivnostCo nejméně kroků a paměti. Doběhne v rozumném čase.

Pseudo-náhodné algoritmy

Některé algoritmy záměrně používají pseudonáhodnost (Quicksort s náhodným pivotem, hashing). Stále jsou deterministické: pokud zafixuješ random seed, dostaneš stejný výsledek. Při různých seedech ale různé pořadí operací.


Zápis algoritmu

Přirozený jazyk

1. Vezmi první prvek seznamu a označ ho jako "nejmenší".
2. Procházej zbytek seznamu.
3. Pokud najdeš menší prvek, označ ho jako "nejmenší".
4. Po projití celého seznamu vrať označený prvek.

Plus: čitelné pro každého. Mínus: nepřesné, nekonkrétní, jazyk je víceznačný.

Pseudokód

Strukturovaný zápis podobný kódu, ale bez syntaxe konkrétního jazyka.

function NajdiMin(pole):
    min = pole[0]
    for i from 1 to length(pole) - 1:
        if pole[i] < min:
            min = pole[i]
    return min

Plus: přesný, ale flexibilní. Mínus: žádný standard, každý si píše po svém.

Vývojový diagram (flowchart)

Grafické znázornění pomocí bloků a šipek.

TvarVýznam
OválStart / konec
ObdélníkOperace, příkaz
KosočtverecPodmínka (rozhodnutí)
RovnoběžníkVstup / výstup
ŠipkyTok programu

image.png

Plus: vizuální, dobré pro výuku. Mínus: pro složité algoritmy nepřehledné.

Zdrojový kód

python
def najdi_min(pole):
    min_val = pole[0]
    for x in pole[1:]:
        if x < min_val:
            min_val = x
    return min_val

Plus: spustitelný. Mínus: vázaný na jazyk.


Typy algoritmů

Podle způsobu řešení

TypPrincipPříklad
IteračníCyklus opakuje krokyfor, while faktoriál
RekurzivníFunkce volá sama sebeRekurzivní faktoriál, traversal stromu

Iterační faktoriál

python
def factorial(n):
    result = 1
    for i in range(2, n + 1):
        result *= i
    return result

Rekurzivní faktoriál

python
def factorial(n):
    if n == 0:           # base case (nutný!)
        return 1
    return n * factorial(n - 1)

Důležité: rekurzivní funkce MUSÍ mít base case (případ ukončení). Bez něj se zacyklí, dojde paměť na zásobníku a program spadne se stack overflow.

Iterace vs rekurze

IteraceRekurze
PaměťKonstantníRoste s hloubkou zanoření
RychlostTypicky rychlejšíPomalejší (volání funkce)
ČitelnostImperativníČasto elegantnější (stromy, fraktály)
RiskŽádný zvláštníStack overflow při hluboké rekurzi
OptimalizaceŽádná speciálníTail-call optimization (ne všude)

Některé problémy jsou přirozeně rekurzivní (binární strom, Quicksort, fraktály), jiné iterativní (sumy, průměry).

Podle účelu

TypPříklady
VýpočetníFaktoriál, mocnina, Fibonacci, Eukleidův algoritmus
TřídicíBubble Sort, Merge Sort, Quick Sort
VyhledávacíLineární, binární, hashování
GrafovéDijkstra, BFS, DFS, A*
ŠifrovacíAES, RSA, SHA-256
KompreseLZ77, Huffmanovo kódování
Strojové učeníLineární regrese, k-means, neuronové sítě

Algoritmická složitost

Složitost popisuje, jak rychle roste zdroje (čas nebo paměť) potřebné pro algoritmus s rostoucí velikostí vstupu n.

Časová vs prostorová složitost

Časová složitostProstorová složitost
MěříKolik operací algoritmus provedeKolik paměti potřebuje
OznačeníStejné notace (O, Ω, Θ)Stejné notace
PříkladBubble sort: O(n²)Bubble sort: O(1) (in-place)
PříkladMerge sort: O(n log n)Merge sort: O(n) (potřebuje extra pole)

Často jde proti sobě: rychlejší algoritmus může potřebovat víc paměti (memoizace v DP).

Asymptotická notace

Drobnost k opravě původních zápisků: "Big O notace popisuje nejhorší případ" je zjednodušení. Tady je random Claude ego-tripping bullshit, kterej 100% nebude zajímat komisi:

NotaceVýznamAnalogie
Big O O(f(n))Horní odhad růstu"Nejhůř roste jako..."
Big Omega Ω(f(n))Dolní odhad růstu"Nejmíň roste jako..."
Big Theta Θ(f(n))Těsný odhad růstu"Roste přesně jako..."

V praxi se ale Big O používá pro worst case time complexity jako default. Když řekneš "Bubble Sort je O(n²)", je to konvenčně worst case.

Best, worst a average case

AlgoritmusWorstSpace
Quick SortO(n²)O(log n)
Merge SortO(n log n)O(n)
Bubble SortO(n²)O(1)
Insertion SortO(n²)O(1)
Binary SearchO(log n)O(1)

Třídy složitosti od nejlepší po nejhorší

NotaceNázevPříklad operace
O(1)KonstantníPřístup k prvku pole, hashmap lookup
O(log n)LogaritmickáBinární vyhledávání, balanced tree ops
O(n)LineárníProcházení pole, lineární vyhledávání
O(n log n)LinearitmickáEfektivní třídění (Merge, Quick, Heap)
O(n²)KvadratickáBubble Sort, vnořené cykly
O(n³)KubickáNaivní násobení matic
O(2ⁿ)ExponenciálníGenerování všech podmnožin, brute force
O(n!)FaktoriálníGenerování všech permutací, traveling salesman brute

Pravidla zjednodušování

  1. Drop konstanty: O(2n) → O(n), O(3n²) → O(n²)
  2. Drop nižší řády: O(n² + n) → O(n²)
  3. Suma cyklů: O(n) + O(m) = O(n + m), často zjednodušeno na O(max(n, m))
  4. Násobek vnořených cyklů: O(n) × O(m) = O(n · m)

Klasické algoritmy k zapamatování

Fibonacci

python
# Naivně rekurzivně: O(2^n), pomalé
def fib(n):
    if n < 2: return n
    return fib(n-1) + fib(n-2)

# S memoizací (dynamic programming): O(n)
def fib_dp(n, cache={}):
    if n in cache: return cache[n]
    if n < 2: return n
    cache[n] = fib_dp(n-1, cache) + fib_dp(n-2, cache)
    return cache[n]

# Iterativně: O(n) čas, O(1) paměť
def fib_iter(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return a

Binární vyhledávání

Pro seřazené pole, O(log n):

python
def binary_search(arr, target):
    low, high = 0, len(arr) - 1
    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1
    return -1

Třídicí algoritmy podrobně

AlgoritmusBestAvgWorstSpaceStabilní?In-place?
Bubble SortO(n)O(n²)O(n²)O(1)AnoAno
Insertion SortO(n)O(n²)O(n²)O(1)AnoAno
Selection SortO(n²)O(n²)O(n²)O(1)NeAno
Merge SortO(n log n)O(n log n)O(n log n)O(n)AnoNe
Quick SortO(n log n)O(n log n)O(n²)O(log n)NeAno
Heap SortO(n log n)O(n log n)O(n log n)O(1)NeAno
Counting SortO(n + k)O(n + k)O(n + k)O(k)AnoNe
Radix SortO(d(n + k))O(d(n + k))O(d(n + k))O(n + k)AnoNe

Praktická volba:

  • Pro malé datasety (< 50): Insertion Sort (jednoduchý, rychlý na malém)
  • Pro obecné použití: Quick Sort (rychlý v praxi) nebo built-in (typicky TimSort: hybrid Merge + Insertion)
  • Když potřebuješ stabilitu: Merge Sort
  • Pro celočíselné klíče v omezeném rozsahu: Counting Sort, Radix Sort (umí dokonce O(n))
  • Pro paměťově omezené prostředí: Heap Sort

Příklady třídění

Bubble Sort (jednoduchý, pomalý)

python
def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(0, n - i - 1):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]

Quick Sort

python
def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quick_sort(left) + middle + quick_sort(right)

Vyhledávací algoritmy

AlgoritmusVyžadujeSložitost
LineárníCokoliO(n)
BinárníSeřazené poleO(log n)
InterpolačníRovnoměrně rozdělená dataO(log log n) průměrně
HashingHash tabulkaO(1) průměrně, O(n) worst
python
# Lineární vyhledávání: O(n)
def linear_search(arr, target):
    for i, x in enumerate(arr):
        if x == target:
            return i
    return -1

Rychlý tahák

PojemKlíčová fakta
AlgoritmusKonečná posloupnost přesných kroků vedoucích k cíli
Algoritmus vs programAbstrakce vs konkrétní implementace
Algoritmus vs heuristikaGarance vs odhad
7 vlastnostíKonečnost, resultativnost, jednoznačnost, vstupnost, obecnost, správnost, efektivnost
ZápisPřirozený jazyk, pseudokód, vývojový diagram, kód
Iterace vs rekurzeCyklus vs volání sebe sama (s base case)
Rekurze riskStack overflow bez base case
ParadigmataBrute force, divide & conquer, dynamic programming, greedy, backtracking
Big OAsymptotický horní odhad růstu
Časová složitostPočet operací
Prostorová složitostSpotřeba paměti
O(1)Konstantní (array index, hash lookup)
O(log n)Logaritmická (binární vyhledávání)
O(n)Lineární (procházení pole)
O(n log n)Linearitmická (efektivní třídění)
O(n²)Kvadratická (Bubble Sort)
O(2ⁿ)Exponenciální (brute force)
Quick Sort worstO(n²) (ne O(n log n)!)
Stabilní tříděníZachová pořadí stejných prvků
Eukleidův algoritmusNSD dvou čísel, O(log min)
Binární vyhledáváníJen seřazené pole, O(log n)
P vs NPSlavný nevyřešený problém

Tipy pro ústní zkoušku

Jak začít

"Algoritmus je konečná posloupnost přesně definovaných kroků, které vedou k vyřešení problému. Jméno pochází z perského matematika al-Chvárizmího. Algoritmy se zapisují různě: přirozeným jazykem, pseudokódem, vývojovým diagramem nebo přímo kódem v programovacím jazyce. Důležitým aspektem je algoritmická složitost, která popisuje, jak rychle rostou zdroje při větším vstupu."

Co komise typicky chce slyšet

  • Definice s důrazem na konečnost a přesnost.
  • Vlastnosti alespoň 5-7 hlavních.
  • Způsoby zápisu s ukázkou pseudokódu.
  • Iterace vs rekurze s příkladem (faktoriál).
  • Big O základní třídy s příklady (O(1), O(log n), O(n), O(n log n), O(n²)).
  • Konkrétní třídicí algoritmy s jejich složitostí.

Doplňky, které komisi potěší

  • Původ slova z al-Chvárizmí.
  • Algoritmické paradigma: divide & conquer (Merge Sort), dynamic programming (Fibonacci s cache), greedy (Dijkstra).
  • Big O není jen worst case, ale asymptotický horní odhad. Existují i Ω a Θ.
  • Quick Sort worst case je O(n²), ne O(n log n) (chyták).
  • Stabilita a in-place vlastnosti třídění.
  • Eukleidův algoritmus nebo Sito Eratosthena jako klasické příklady.
  • P vs NP jako legendární nevyřešený problém.

Časté chytáky

OtázkaOdpověď
Je Quick Sort O(n log n)?V průměru ano, ale worst case je O(n²). Proto se používá náhodný pivot.
Co je base case v rekurzi?Případ ukončení, který nevolá funkci znovu. Bez něj = stack overflow.
Big O = nejhorší případ?Konvenčně ano, ale technicky Big O je horní odhad růstu, nezávisle na případu.
Proč Merge Sort potřebuje O(n) paměti?Není in-place, potřebuje pomocné pole pro slučování.
Co je stabilní třídění?Zachová původní pořadí prvků se stejnou hodnotou. Důležité při třídění objektů podle více klíčů.
Algoritmus vs program?Algoritmus je abstraktní postup, program je konkrétní implementace v jazyce.
Rozdíl algoritmus a heuristika?Algoritmus garantuje správný výsledek, heuristika je rychlejší odhad bez garance optima.