# Programátorské strategie

## Algoritmizace

**Proč se jí zabývat?**
- rozvíjí abstraktní a logické myšlení potřebné nejen pro techniky
- existují hotová řešení na různé problémy, ale vždy narazíme na trochu jiné problémy
+ je potřeba znát
	+ základní problémy a jejich řešení
	+ principy a techniky k řešení velké oblasti neznámých problémů

**Algoritmus**
- postup k vyřešení určitého úkolu
- musí řešit obecný, dobře specifikovaný problém
- procedura, která libovolná možná vstupní data transformuje na požadovaný výstup
- **algoritmus** - vždy vede k cíli, **heuristika** - nemusí vést vždy k cíli

### Správnost a účinnost algoritmu

**Cíl snažení**
- algoritmy správné, efektivní a snadno implementovatelné
- ne vždy je možné vše najednou

**Zlepšení výkonu**
- lepší algoritmus > lepší počítač
- kdy nehledat účinnější řešení:
	- poběží jen několikrát
	- výpočet přes noc je OK
- optimalizovat *bottleneck* (kritické místo - 90 % času v 10 % kódu)

### Robustnost algoritmu

**Cíl snažení**
- algoritmy odolné vůči numerickým aj. chybám
- singulární případy: při první úvaze ignorovat, poté zahrnout

**Robustnost**
- malá chyba nesmí vést k selhání
- algoritmy často odvozeny např. pro nekonečnou přesnost reálných čísel

### Analýza algoritmů

**Cíl snažení**
- hodnocení a porovnávání algoritmů nezávislé na typu počítače a na jazyku
- typické chování pro očekávaná vstupní data

**Nástroj**
- asymptotická analýza složitosti
- experimentální otestování na reprezentativních vstupních datech

#### Složitost

- paměťová x časová x předzpracování
- nejčastěji nás zajímá nejhorší případ a očekávaný případ
	- => složitost v nejhorším případě, očekávaná složitost

**Symbolika**
- $O(f(n))$ - horní mez
- $\Omega(f(n))$ - dolní mez
- $\Theta(f(n))$ - omezeno shora i zdola (optimální algoritmus)

**Časová složitost algoritmu**
- nejdelší doba výpočtu potřebná pro vstup velikosti $n$

**Časová složitost problému**
- časová složitost nejrychlejšího algoritu řešící tento problém
- $O(n^2)$ - najít algoritmus, který vyřeší tento problém nejvýše v čase $cn^2$
- $\Omega(n^2)$ - dokázat, že žádný algoritmus nedokáže problém vyřešit rychleji

#### Experimentální ověření složitosti

- spotřeba času a paměti jako funkce velikosti vstupu
- pro zmenšení chyby měřit více opakování, bez I/O, pro více datových množin, pro více typů dat
- spočítat $t/f(n)$, zkoumat průměrné a nejhorší chování

**Očekávaná složitost (Expected complexity)**
- odhad pozorovaného chování algoritmu, často odhad podle implementace, závisí též na očekávaném typu vstupních dat

#### Standardní třídy složitosti problému

- **P** - problém v této třídě řešitelný výpočty v polynomiálním čase
- **NP** - řešitelný v polynomiálním čase nedeterministicky
	- nevíme, jak řešit polynomiálně, ale umíme ověřit v polynomiálním čase řešení
	- dnes kolem 3000 problémů
- **NP-úplné** - není známo žádné polynomiální řešení
	- nebylo dokázáno, že neexistuje

### Hledání řešení neznámého problému

Pomáhá klást si správné otázky (v uvedeném pořadí):
1. Opravdu problému rozumím?
	- Co je vstupem?
	- Jaký přesně má být výstup?
	- Umím sestavit malý příklad a vyřešit ručně? Co se stane, když to zkusím?
	- Jak moc je pro mou aplikaci důležité najít vždy přesné, optimální řešení? Nestačí něco, co obvykle funguje docela dobře?
	- Jak velká je typická instance mého problému? 10? 1000? 1 mil.?
	- Jak důležitá je pro moji aplikaci rychlost?
	- Musí být problém vyřešen za 1s? 1 min? 1 h? 1 den?
	- Kolik času a úsilí mohu dát do implementace?
	- Budu řešit numerický problém? Grafový? Geometrický? Se znakovým řetězcem? Více možných formulací? Která se zdá nejlehčí?
2. Umím najít jednoduchý algoritmus nebo heuristiku řešící daný problém?
	-  Umím najít algoritmus správně řešící můj problém prohledáním všech podmnožin a výběrem nejlepší? (Pokud ano, jsem si jist správností odpovědi? Umím změřit kvalitu nalezeného řešení? Stačí časově? Pokud ne, mám problém dostatečně definovaný, aby se dal vyřešit?)
	- Umím problém vyřešit opakovaným výběrem nejlepšího? Opakovaným náhodným výběrem? (Pokud ano, pro jaký vstup to funguje dobře, špatně? Je to rychlé?)
3. Není můj problém v katalogu algoritmických problémů?
	- Pokud ano, co je o problému známo? Není k mání implementace řešení?
	- Pokud ne, je to správné místo? Umím hledat v knihách?
	- Co Web?
4. Existující speciální případy, které umím řešit přesně?
	- Umím to, pokud ignoruji některé parametry?
	- Co se stane, když některé parametry nastavím na triviální hodnoty, jako je 0, 1?
	- Umím problém zjednodušit na případ, který je možné řešit přesně? Je teď triviální nebo stále zajímavý?
	- Pokud už umím řešit spec. případ, proč nejde řešení použít pro obecnější problém?
	- Je můj problém spec. případ některého obecného problému?
5. Které ze standardních paradigmat návrhu algoritmů je nejvhodnější pro můj problém?
	- Je možné položky setřídit? Ulehčí to řešení? (SORT)
	- Je možné problém rozdělit na 2 nebo více podproblémů? Malý a velký? Levý a pravý? 2 stejně velké? (D&C)
	- Má vstup nebo řešení přirozené pořadí zpředu dozadu, zleva doprava (řetězce, permutace, listy stromu)? (DP)
	- Opakuje se stejná operace nad stejnými daty (hledání), kterou by urychlila pomocná dat. struktura? (slovník, hašovací tabulka, hromada, prioritní fronta…)
	- Lze použít náhodné vzorkování pro výběr dalšího objektu? Výběr nejlepší z náhodně vybraných konfigurací? (řízená náhodnost, např. SA)?
	- Problém pro lineární programování? Celočíselné programování?
6. Jsem stále ztracen(a)?
	- Nenajmu si na to experta?
	- Nezkusím otázky projít znova? (Změnily se moje odpovědi?)