Přidání 6. přednášky z PPA2

This commit is contained in:
Filip Znachor 2023-03-23 22:07:06 +01:00
parent f6c70d86b0
commit b4f7ee9dd8

120
KIV PPA2/Prednaska06.md Normal file
View file

@ -0,0 +1,120 @@
# Odstranění rekurze
**Proč?**
- problémy s hloubkou zanoření (velikost zásobníku je malá)
- neefektivní , protože se při volání metod kopírují hodnoty skutečných parametrů do zásobníku
### Koncová rekurze
- kód končí jediným rekurzivním voláním
- nejjednodušší druh rekurze, je snadné přepsat na cyklus
### Eliminace vlastním zásobníkem
- použití zásobníku jako seznamu úkolů (například třída `Task`)
- položky v zásobníku budou obsahovat:
- co se má udělat (parametry)
- v jaké čísti úkolu jsme (segment)
- data nutná pro pokračování výpočtu (mezivýsledky)
- pokud je potřeba pro dokončení úkolu rekurze, přidá se do zásobníku nový úkol
- až se dojde k triviálnímu úkolu, data se předají dalšímu úkolu
**Jak rekurzi odstranit?**
- rozdělíme kód na segmenty mezi rekurzivními voláními
- na začátku do zásobníku vložíme pouze hlavní úkol
- zpracováváme položky zásobníku, dokud není prázdný
- místo rekurzivního volání:
- uložíme stav výpočtu položky na vrcholu zásobníku (stavové proměnné)
- zvýšíme segment na vrcholu zásobníku (jsme o jednu část úkolu dál)
- do zásobníku přidáme nový úkol reprezentující rekurzi
- ukončíme zpracování aktuálního úkolu (smyčka se k němu vrátí později)
- místo vrácení hodnoty:
- uložíme výsledek do proměnné `result`
- odebereme úkol z vrcholu zásobníku
- při pokračování dalším segmentem:
- obnovíme stavové proměnné z položky na vrcholu zásobníku
- výsledek posledního rekurzivního volání se nachází v proměnné `result`
- na konci vrátímě proměnnou `result`
**Závěr**
- každou rekurzivní funkci je možné přepsat bez použití rekurze
- pracný mechanický postup
- horší přehlednost kódu
- potřeba implementace zásobníku
- přepsání bez rekurze zachovává třídu složitosti (nezajišťuje efektivitu)
- pro nalezení efektivnější implementace mechanický postup neexistuje
# Fronta
- abstraktní datová struktura
- podobá se zásobníku
- FIFO - first in, first out
**Operace**
- přidání prvku na konec
- vybrání prvku na začátku začátku
- odebrání prvku na začátku začátku
### Implementace spojovým prvkem
- velmi podobná zásobníku
- kromě odkazu na první prvek uchovává i **odkaz na poslední prvek**
**Složitost operací**
- všechny $\Theta(1)$
- vyšší náročnost na paměť
### Implementace polem
- velmi podobná zásobníku
- po odebrání vznikají prázdná místa v poli
- je možné je využít pro přidávání
- struktura obsahuje:
- index prvního prvku
- počet obsazených indexů
- při přidávání prvku:
- kontrolujeme, jestli se prvek do pole vejde
- pokud je **místo na začátku**, vložíme prvek na začátek pole
- pokud je **pole plné** zvětšíme pole a zkopírujeme od indexu prvního prvku až do délky pole
- využijeme modula - pomocí něj index "přeteče" na začátek pole
- máme pole o 5 prvcích
- vkládáme na index 5, nicméně 5 % 5 je 0 (začátek pole)
**Složitost operací**
- vybrání/odebrání prvního prvku $\Theta(1)$
- přidání prvku na konec:
- většinou $\Theta(1)$
- při zvětšení pole $\Theta(n)$
- v průměru $\Theta(1)$
# Třídy s typovým parametrem
- často potřeba kolekce pro různé datové typy
- není vhodné vytvářet samostatné kolekce (třídy) pro různé datové typy
### Řešení pomocí Object
- všechny třídy dědí z Object
- vkládání není problém
- při vybrání prvku je potřeba **jej přetypovat**
- případná chyba se objeví až za běhu programu
**Obalovací třída**
- anglicky wrapper
- poskytuje metody, které provádějí **přetypování na správnou třídu**
- skrývá vnitřní implementaci s `Object`
- je potřeba ji vytvořit pro každý datový typ
**Generická třída**
- třída s typovým parametrem `class MyStack<T>`
- datový typ `Object` poté nahradíme typem `T`
- bohužel nefunguje všude
- typ `T` pouze přebíráme a vracíme
- vnitřně používáme `Object`, který poté přetypujeme
- typovým parametrem nemůže být primitivní datový typ
- využijeme obalovací třídu (`Integer`, `Double`, ...)
- přetypování (boxing a unboxing) probíhá automaticky, je ale dobré o něm vědět
- někdy je potřeba, aby typový parametr něco uměl
- je možné použít rozhraní
- `class MyStack<T extends IProcessable>`
- pokud potřebujeme použít nějakou metodu tohoto rozhraní ve třídě, můžeme `Object` přetypovat na `T`