diff --git a/KIV PPA2/Prednaska02.md b/KIV PPA2/01. Generické programování.md similarity index 68% rename from KIV PPA2/Prednaska02.md rename to KIV PPA2/01. Generické programování.md index 93dd858..7d83b74 100644 --- a/KIV PPA2/Prednaska02.md +++ b/KIV PPA2/01. Generické programování.md @@ -9,7 +9,7 @@ ## Rozhraní (interface) -- popisuje, co nějaká třída umí: hlavičky metod +- popisuje, co nějaká třída umí: **hlavičky metod** - neříká nic o tom, jak jsou metody implementovány - různé třídy mohou implementovat stejné rozhraní - jedna třída může implementovat více rozhraní @@ -41,37 +41,12 @@ - dědit lze vždy jen od **jednoho** předka - referenci na potomka je možné kdykoli přetypovat na referenci na předka - přetypovává se **reference**, nikoli instance samotná - - obráceně ne (runtime error) => předek nemusí implementovat vše co potomek - - každou referenci je možné přetypovat na referenci na `Object` + - obráceně ne (runtime error), předek nemusí implementovat vše, co potomek + - každou referenci je možné přetypovat na `Object` ## Polymorfismus - instanci potomka lze použít všude kde se očekává předek - parametr metody - pole předků - - ... - -# Rekurzivní programy - -- programy, které volají sami sebe -- rekurze, musí někdy skončit! - -## Přímá rekurze - -- metoda volá přímo sebe sama -- je vidět na první pohled - -## Nepřímá rekurze - -- `a` volá `b`, `b` volá `a` - -## Problémy rekurze - -- problémy s hloubkou zásobníku - - spíše programátorská chyba - **přetečení zásobníku** - - pro mnoho praktických problémů je rekurze dostatečná - - Java umožňuje nastavit velikost zásobníku -- často lze zapsat do nerekurzní formy - - nerekurzivní zápis je **často rychlejší** - - zrychlení se projeví, pokud je samotný vykonávaný kód triviální - - někdy je přepsání poměrně složité \ No newline at end of file + - ... \ No newline at end of file diff --git a/KIV PPA2/02. Rekurzivní programy.md b/KIV PPA2/02. Rekurzivní programy.md new file mode 100644 index 0000000..368ad55 --- /dev/null +++ b/KIV PPA2/02. Rekurzivní programy.md @@ -0,0 +1,24 @@ +# Rekurzivní programy + +- programy, které volají sami sebe +- rekurze, musí někdy skončit! + +## Přímá rekurze + +- metoda volá přímo sebe sama +- je vidět na první pohled + +## Nepřímá rekurze + +- `a` volá `b`, `b` volá `a` + +## Problémy rekurze + +- problémy s hloubkou zásobníku + - spíše programátorská chyba - **přetečení zásobníku** + - pro mnoho praktických problémů je rekurze dostatečná + - Java umožňuje nastavit velikost zásobníku +- často lze přepsat do nerekurzivní formy + - nerekurzivní zápis je **často rychlejší** + - zrychlení se projeví, pokud je samotný vykonávaný kód triviální + - někdy je přepsání poměrně složité \ No newline at end of file diff --git a/KIV PPA2/Prednaska03.md b/KIV PPA2/03. Výpočetní složitost.md similarity index 91% rename from KIV PPA2/Prednaska03.md rename to KIV PPA2/03. Výpočetní složitost.md index 804e45e..a277d36 100644 --- a/KIV PPA2/Prednaska03.md +++ b/KIV PPA2/03. Výpočetní složitost.md @@ -1,16 +1,16 @@ # Výpočetní složitost -- doba výpočtu T(n) v závislosti na vstupu n +- doba výpočtu $T(n)$ v závislosti na vstupu $n$ - je důležité určit, co je důležité - - zajímá nás, co se děje, když n roste + - zajímá nás, co se děje, když $n$ roste - různé funkce rostou různě rychle - druhy algoritmů - rychle rostoucí funkce = neefektivní algoritmus - pomalu rostoucí funkce = efektivní algoritmus - záleží na tom, jestli se funkce vejde pod jinou - například lineární pod kubickou - - ne hned, ale od nějakého $n_0$ ano - - nezáleží na násobku, jen to $n_{0}$ bude dál + - nemusí se vejít hned, ale třeba od nějakého $n_0$ ano + - nezáleží na násobku $n$, jen to $n_{0}$ bude dál ## O-notace @@ -76,7 +76,7 @@ Význam funkcí může být: - čas výpočtu pro nejhorší možný vstup velikosti n - průměrný čas výpočtu pro vstup velikosti n - počet instrukcí pro ... -- množství paměti nutné pro zpracování ... +- množství paměti nutné pro zpr# 1020acování ... - ... Je ale potřeba nesrovnávat hrušky s pomeranči. @@ -85,5 +85,5 @@ Je ale potřeba nesrovnávat hrušky s pomeranči. ## Určení výpočetní složitosti programu - je potřeba určit funkci $g(n)$ -- při určování můžeme zanedbat časy jednotlivých instrukcí, **pokud jsou opravdu konstatní** (nezávislá na parametru n) +- při určování můžeme zanedbat časy jednotlivých instrukcí, **pokud jsou opravdu konstantní** (nezávislé na parametru $n$) - výpočetní složitost neřeší rozdílné výkony počítačů \ No newline at end of file diff --git a/KIV PPA2/Prednaska04.md b/KIV PPA2/04. Řazení.md similarity index 99% rename from KIV PPA2/Prednaska04.md rename to KIV PPA2/04. Řazení.md index dd55e95..e5e99f7 100644 --- a/KIV PPA2/Prednaska04.md +++ b/KIV PPA2/04. Řazení.md @@ -95,7 +95,7 @@ Nalezení pořadí (indexů) pro množinu prvků podle nějakého uspořádání - procházíme obě posloupnosti současně (držíme aktuální index pro obě) - do výsledné posloupnosti zapíšeme menší ze dvou aktuálních prvků - v příslušné posloupnosti se posuneme na další prvek -- efentivní implementace: +- efektivní implementace: - pracuje s úseky původního pole a eliminuje testování konce polí A a B - alokuje se dočasné pole - v poli se vytvoří tzv. bitonická posloupnost diff --git a/KIV PPA2/05. Abstraktní datové typy.md b/KIV PPA2/05. Abstraktní datové typy.md new file mode 100644 index 0000000..ed55b7f --- /dev/null +++ b/KIV PPA2/05. Abstraktní datové typy.md @@ -0,0 +1,25 @@ +# Abstraktní datové typy + +- abstraktní - nezabývá se rozdíly, ale tím, co je **společné** +- definují možné operace s daty +- nedefinují způsob uložení dat ani provedení operací (implementaci) + +**ADT vs rozhraní** +- ADT můžou být implementovány různě v různých jazycích +- rozhraní jen způsob implementace ADT v Javě + +**Kolekce** +- datové struktury, které uchovávají sadu prvků +- umožňují operace s daty + - přidat prvek (na začátek, na konec, za/před prvek, s nějakým klíčem, ...) + - vybrat prvek (na začátku, na konci, na indexu, s extrémním klíčem, ...) + - odebrat prvek (na začátku, na konci, na indexu, s extrémním klíčem, ...) + +**Implementace ADT** +- určuje složitost operací +- obvykle reprezentována třídou + +**Úkol programátora** +- vybrat vhodnou ADT +- vybrat vhodnou implementaci ADT +- vědět, co ADT dělá (jaká je složitost operací) \ No newline at end of file diff --git a/KIV PPA2/Prednaska05.md b/KIV PPA2/06. ADT Zásobník.md similarity index 72% rename from KIV PPA2/Prednaska05.md rename to KIV PPA2/06. ADT Zásobník.md index e91a886..9ce6dd9 100644 --- a/KIV PPA2/Prednaska05.md +++ b/KIV PPA2/06. ADT Zásobník.md @@ -1,29 +1,3 @@ -# Abstraktní datové typy - -- abstraktní - nezabývá se rozdíly, ale tím, co je **společné** -- definují možné operace s daty -- nedefinují způsob uložení dat ani provedení operací (implementaci) - -**ADT vs rozhraní** -- ADT můžou být implementovány různě v různých jazycích -- rozhraní jen způsob implementace ADT v Javě - -**Kolekce** -- datové struktury, které uchovávání sadu prvků -- umožňují operace s daty - - přidat prvek (na začátek, na konec, za/před prvek, s nějakým klíčem, ...) - - vybrat prvek (na začátku, na konci, na indexu, s extrémním klíčem, ...) - - odebrat prvek (na začátku, na konci, na indexu, s extrémním klíčem, ...) - -**Implementace ADT** -- určuje složitost operací -- obvykle reprezentována třídou - -**Úkol programátora** -- vybrat vhodnou ADT -- vybrat vhodnou implementaci ADT -- vědět, co ADT dělá (jaká je složitost operací) - # Zásobník - abstraktní datová struktura @@ -69,7 +43,7 @@ - $n = 2^k + 1, o = 2^{k+1} - 1$ - $o = 2(2k) - 1 = 2(2k + 1) - 3 = 2n - 3 < 2n$ - **závěr**: - - složitost oprace přidání je $\mathcal{O}(n)$ + - složitost operace přidání je $\mathcal{O}(n)$ - průměrná složitost je $\Theta(1)$ - při zvětšování **o konstantu** to neplatí - přidání n prvků $\Omega(n^2)$ @@ -104,7 +78,7 @@ Tyto aspekty není potřeba se učit, vyplývají ze způsobu implementace. #### Použití z klientské třídy -- použití obou implementací je úplně stejné +- použití obou implementací je úplně stejné - uživatel vůbec nemusí vědět, co se děje uvnitř - vnitřní data jsou udržována v konzistentním stavu diff --git a/KIV PPA2/07. Odstranění rekurze.md b/KIV PPA2/07. Odstranění rekurze.md new file mode 100644 index 0000000..f4a1ab7 --- /dev/null +++ b/KIV PPA2/07. Odstranění rekurze.md @@ -0,0 +1,45 @@ +# 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íme 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 \ No newline at end of file diff --git a/KIV PPA2/08. ADT Fronta.md b/KIV PPA2/08. ADT Fronta.md new file mode 100644 index 0000000..b6df549 --- /dev/null +++ b/KIV PPA2/08. ADT Fronta.md @@ -0,0 +1,42 @@ +# 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 +- odebrání prvku na 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)$ \ No newline at end of file diff --git a/KIV PPA2/09. Třídy s typovým parametrem.md b/KIV PPA2/09. Třídy s typovým parametrem.md new file mode 100644 index 0000000..3053818 --- /dev/null +++ b/KIV PPA2/09. Třídy s typovým parametrem.md @@ -0,0 +1,34 @@ +# 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 +- **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` +- **problém** + - je potřeba ji vytvořit pro každý datový typ + +**Generická třída** +- **"správné" řešení** +- třída s typovým parametrem `class MyStack` + - 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` + - pokud potřebujeme použít nějakou metodu tohoto rozhraní ve třídě, můžeme `Object` přetypovat na `T` \ No newline at end of file diff --git a/KIV PPA2/Prednaska07.md b/KIV PPA2/10. ADT Seznam.md similarity index 55% rename from KIV PPA2/Prednaska07.md rename to KIV PPA2/10. ADT Seznam.md index a54240f..50d7231 100644 --- a/KIV PPA2/Prednaska07.md +++ b/KIV PPA2/10. ADT Seznam.md @@ -16,7 +16,7 @@ Jak specifikovat pozici? - ukazuje na prvek - některé operace problematické (např. vložení - před nebo za prvek?) - ukazuje mezi prvky - - jednožnačné vkládání: sem + - jednoznačné vkládání: sem - vybírání/odebírání dohodou - třeba prvek napravo ### Implementace spojovou strukturou @@ -43,7 +43,7 @@ Jak specifikovat pozici? - seznam neumožňuje prácí **na více místech** - vznik odděleného ukazovátka od dat - **iterátoru** (návrhový vzor) -- třída, která má aktuální index `current` a referenci `list +- třída, která má aktuální index `current` a referenci `list` - stejná implementace jako u seznamu (místo `first` se použije `list.first`)` **Operace** @@ -75,84 +75,4 @@ Jak specifikovat pozici? - pro index následovníka (`next`) - prázdného či obsazeného prvku - index začátku `first` - index volného pole `empty` -- index aktuálního prvku `current` - -# Kolekce v Javě - -Java poskytuje knihovní třídy pro základní implementaci kolekcí - -### Třída `LinkedList` - -- spojová datová struktura - -**Operace** -- operace v $\mathcal O(1)$ - - `void addFirst(T)`, `void addLast(T)` - - `T getFirst()`, `T getLast()` - - `void removeFirst()`, `void removeLast()` -- operace v $\Omega(n)$ - - `void add(int, T)` - vložení na daný index - - `T get(int)` - získání z indexu - - `void remove(int)` - smazání z indexu -- `Iterator iterator()` -- `ListIterator listIterator()` - lepší iterátor - -### Třída `ArrayList` - -- dynamické pole - -**Operace** -- operace v $\mathcal O(1)$ - - `void add(T)` - - `T get(int)` -- operace v $\Omega(n)$ - - `void remove(int) -- operace pro získání iterátorů - ale s **vyšší složitostí**! - -### Třída `Iterator` - -**Operace** -- `T next()` - vrátí přeskočený prvek a posune se dopředu - - na konci vyhodí výjimku -- `boolean hasNext()` - existence dalšího prvku -- `void remove()` - odstraní poslední prvek vrácený metodou `next()` - - před dalším odstraněním potřeba zavolat `next()` -- chybí: - - návrat na začátek (stačí si vyžádat nový iterátor) - - metoda pro vložení prvku - -**Vylepšený `ListIterator`** -- má navíc: - - `T previous()` - vrátí hodnotu předchozího prvku a posune iterátor zpět - - na začátku vyhodí výjimku - - `void add(T)` - vloží prvek na pozici iterátoru - -### Rozhraní `Queue` - -- rozhraní fronty -- `LinkedList` toto rozhraní implementuje - -**Operace** -- `void add()` -- `T element()` -- `T remove()` - -### Třída `Stack` - -implementace zásobníku dynamickým polem - `ArrayList` -- stejné metody poskytuje i `LinkedList` - -**Operace** -- `void push(T)` -- `T pop()` -- `T peek()` - -### Obecná zásada - -Kolekce v čase $\mathcal O(1)$ umí buď -1) vybrat prvek na specifickém indexu, anebo -2) vyjmout/vložit prvek na pozici iterátoru, - -ale nikdy ne obojí současně! - -Najít i-tý prvek ve spojovém seznamu zabere vždy $\Omega(n)$. \ No newline at end of file +- index aktuálního prvku `current` \ No newline at end of file diff --git a/KIV PPA2/11. Kolekce v Javě.md b/KIV PPA2/11. Kolekce v Javě.md new file mode 100644 index 0000000..534ad86 --- /dev/null +++ b/KIV PPA2/11. Kolekce v Javě.md @@ -0,0 +1,79 @@ +# Kolekce v Javě + +Java poskytuje knihovní třídy pro základní implementaci kolekcí + +### Třída `LinkedList` + +- spojová datová struktura + +**Operace** +- operace v $\mathcal O(1)$ + - `void addFirst(T)`, `void addLast(T)` + - `T getFirst()`, `T getLast()` + - `void removeFirst()`, `void removeLast()` +- operace v $\Omega(n)$ + - `void add(int, T)` - vložení na daný index + - `T get(int)` - získání z indexu + - `void remove(int)` - smazání z indexu +- `Iterator iterator()` +- `ListIterator listIterator()` - lepší iterátor + +### Třída `ArrayList` + +- dynamické pole + +**Operace** +- operace v $\mathcal O(1)$ + - `void add(T)` + - `T get(int)` +- operace v $\Omega(n)$ + - `void remove(int)` +- operace pro získání iterátorů - ale s **vyšší složitostí**! + +### Třída `Iterator` + +**Operace** +- `T next()` - vrátí přeskočený prvek a posune se dopředu + - na konci vyhodí výjimku +- `boolean hasNext()` - existence dalšího prvku +- `void remove()` - odstraní poslední prvek vrácený metodou `next()` + - před dalším odstraněním potřeba zavolat `next()` +- chybí: + - návrat na začátek (stačí si vyžádat nový iterátor) + - metoda pro vložení prvku + +**Vylepšený `ListIterator`** +- má navíc: + - `T previous()` - vrátí hodnotu předchozího prvku a posune iterátor zpět + - na začátku vyhodí výjimku + - `void add(T)` - vloží prvek na pozici iterátoru + +### Rozhraní `Queue` + +- rozhraní fronty +- `LinkedList` toto rozhraní implementuje + +**Operace** +- `void add()` +- `T element()` +- `T remove()` + +### Třída `Stack` + +implementace zásobníku dynamickým polem - `ArrayList` +- stejné metody poskytuje i `LinkedList` + +**Operace** +- `void push(T)` +- `T pop()` +- `T peek()` + +### Obecná zásada + +Kolekce v čase $\mathcal O(1)$ umí buď +1) vybrat prvek na specifickém indexu, anebo +2) vyjmout/vložit prvek na pozici iterátoru, + +ale nikdy ne obojí současně! + +Najít i-tý prvek ve spojovém seznamu zabere vždy $\Omega(n)$. \ No newline at end of file diff --git a/KIV PPA2/Prednaska08.md b/KIV PPA2/12. ADT Tabulka.md similarity index 98% rename from KIV PPA2/Prednaska08.md rename to KIV PPA2/12. ADT Tabulka.md index 5b7d420..e332096 100644 --- a/KIV PPA2/Prednaska08.md +++ b/KIV PPA2/12. ADT Tabulka.md @@ -36,7 +36,7 @@ Ideálně by měly mít všechny (kromě všech klíčů) složitost $\Theta(1)$ **Tabulka s přímým adresováním** - pole, kde index je klíč - problém: - - často neznáme rozsah možnách klíčů + - často neznáme rozsah možných klíčů - počet přípustných klíčů může být velmi velký nebo nekonečný - neřeší složitější klíče - výhoda: splňuje $\Theta(1)$ diff --git a/KIV PPA2/Prednaska09.md b/KIV PPA2/13. ADT Strom.md similarity index 96% rename from KIV PPA2/Prednaska09.md rename to KIV PPA2/13. ADT Strom.md index d4ea202..bb9f777 100644 --- a/KIV PPA2/Prednaska09.md +++ b/KIV PPA2/13. ADT Strom.md @@ -74,7 +74,7 @@ Operace se můžou lišit podle druhu stromu (binární, uspořádaný, ...). - předek vrcholu s indexem i leží na indexu i/2 (celočíselně) - strom o hloubce h má vrcholy s maximálním indexem $2^{h+1} - 1$ - **reprezentace vrcholu**: - - reprezenntován svým indexem + - reprezentován svým indexem - musí mu být přiřazena data, která jsou uložena v poli - **data přiřazená vrcholu**: - uložená do pole na index vrcholu @@ -88,7 +88,7 @@ Operace se můžou lišit podle druhu stromu (binární, uspořádaný, ...). - **nevýhody**: - pouze pro binární stromy - musíme předem znát počet prvků - - alokuje se paměť i přo nepřítomné prvky (nebo referenci) + - alokuje se paměť i pro nepřítomné prvky (nebo referenci) Pozn.: **Úplný binární strom** - pro určitý index k platí: @@ -119,13 +119,14 @@ Pozn.: **Úplný binární strom** - zahájení průchodu zavoláním metody `preorder/inorder/postorder` nad kořenem ### Binární vyhledávací strom (BST) + - reprezentuje uspořádanou množinu prvků - prvky seřazené pomocí klíče - nejjednodušeji `int` - strom je pouze implementací, ADT hierarchický není **Operace** - vložení prvku s klíčem -- oderání prvku s klíčem +- odebrání prvku s klíčem - zjištění přítomnosti prvku s klíčem - nalezení největšího a nejmenšího klíče - vybrání všech prvků v pořadí klíčů diff --git a/KIV PPA2/Prednaska10.md b/KIV PPA2/14. ADT Graf.md similarity index 75% rename from KIV PPA2/Prednaska10.md rename to KIV PPA2/14. ADT Graf.md index be388b1..49c9d91 100644 --- a/KIV PPA2/Prednaska10.md +++ b/KIV PPA2/14. ADT Graf.md @@ -6,7 +6,7 @@ ### Druhy grafů - **Orientovaný graf** - - podchybuje nesymetrické vztahy + - podchycuje nesymetrické vztahy ### Formální definice @@ -24,7 +24,7 @@ - $\vert V\vert$ - počet vrcholů grafu - $\vert E\vert$ - počet hran grafu + $V(G)$ - množina vrcholů grafu $G$ -+ $V(E)$ - množina hran grafu $G$ ++ $E(G)$ - množina hran grafu $G$ - $y \in V$ je sousedem $x \in V$ právě když - existuje orientovaná hrana $E = (x, y)$ - existuje neorientovaná hrana $E, x \in E, y \in E$ @@ -200,4 +200,57 @@ + celkem + úplný, popř. hustý graf nebo implementace sousednosti maticí: $\Omega(\vert V\vert^2)$ + implementace sousednosti seznamem: $\mathcal{O}(\vert V\vert + \vert E\vert)$ - + graf může mít počet hran až $\vert V\vert^2$ \ No newline at end of file + + graf může mít počet hran až $\vert V\vert^2$ + +**Strom dosažitelnosti** +- tvoří se z nějakého určeného vrcholu (kořen) +- ukazuje, jaká je nejkratší cesta do ostatních vrcholů +- reprezentován polem, kde na indexu vrcholu je uložen předek +- nemusí být jednoznačný (může existovat více nejkratších cest) + +#### Prohledávánı́ do hloubky (DFS) + +- Depth-First Search +- algoritmus postupuje do většı́ vzdálenosti od počátečnı́ho vrcholu, pokud může ++ předpokládáme, že označenı́ (mark) je před volánı́m DFS inicializováno na 0 pro všechny vrcholy ++ DFS je potřeba doplnit o nějaký užitečný kód + + záleží to na řešeném problému + +**Značenı́ vrcholů** +- nezpracovaný (”bı́lá”), kód 0 +- rozpracovaný (”šedá”), kód 1 +- dokončený (”černá”), kód 2 + +**Složitost** +- rekurzivní metoda se pro každý vrchol volá pouze jednou - $\Omega(\vert V\vert)$ +- pro každý vrchol se prochází seznam hran: + - reprezentace maticí - $\Omega(\vert V\vert^2)$ + - reprezentace seznamem - $\mathcal{O}(\vert E\vert)$ +- celkem: $\mathcal{O}(\vert V\vert + \vert E\vert)$ při reprezentaci seznamem + - může být i $\Omega(\vert V\vert^2)$, pokud $\vert E\vert = k\vert V\vert^2$ + +**Použití DFS** +- Zjištění dosažitelnosti vrcholu + - pokud předpokládáme, že bude vrchol daleko, je DFS vhodnější než BFS ++ Zjištění cyklu v grafu + + vrchol označíme jedničkou a poté ho znovu hledáme ++ Topologické řazení + + prvně je potřeba ověřit, že graf nemá cykly + + vrcholy jsou činnosti, hrany jsou závislosti + + hrana $A \to B$ značí, že se prvně musí vykonat A a potom až B + + pomocí DFS můžeme snadno určit pořadí činností (pomocí otočeného grafu) + +**DFS bez rekurze** +- pravděpodobně nastanou problémy s hloubkou zásobníku ++ vystačíme si se zásobníkem celých čísel (vrcholů) ++ `segment` (jaký je stav vrcholu) je v označení vrcholu (`mark`) + +**Nejkratší cesta v ohodnoceném grafu** +- velmi častý problém +- ohodnocení: čas, vzdálenost, ... +- úkol: nalézt nejkratší vzdálenost ke všem vrcholům +- **Dijkstrův algoritmus** + - je potřeba prioritní fronta + - přidání dvojice vrchol + ohodnocení + - vybrání/odebrání vrcholu s nejmenším ohodnocením + - změna ohodnocení vrcholu \ No newline at end of file diff --git a/KIV PPA2/Prednaska12.md b/KIV PPA2/15. ADT Prioritní fronta.md similarity index 72% rename from KIV PPA2/Prednaska12.md rename to KIV PPA2/15. ADT Prioritní fronta.md index cd707b6..0c787f9 100644 --- a/KIV PPA2/Prednaska12.md +++ b/KIV PPA2/15. ADT Prioritní fronta.md @@ -75,21 +75,4 @@ + budeme je vytvářet od konce stromu (od listů) - složitost - nejhorší a očekávaná: $\Theta(n \log(n))$ - - paměťová: $\Theta(1)$ - -# Rekapitulace ADT - -**Přístup k datům pomocí indexů** - -| | vybrání | odebrání | přidání | -| ----------------- | ----------- | ---------------------------- | ---------------------------- | -| spojová struktura | $\Theta(n)$ | $\Theta(1)$ pokud byl vybrán | $\Theta(1)$ pokud byl vybrán | -| dynamické pole | $\Theta(1)$ | $\Theta(n)$ | $\Theta(n)$ | - -**Přístup k datům pomocí klíče** - -| | přidání | odebrání | vybrání | vybrání maxima | odebrání maxima | -| ------- | ----------------- | ----------------- | ----------------- | ----------------- | ----------------- | -| Tabulka | $\Theta(1)$ | $\Theta(1)$ | $\Theta(1)$ | $\Theta(n)$ | $\Theta(n)$ | -| BST | $\Theta(\log(n))$ | $\Theta(\log(n))$ | $\Theta(\log(n))$ | $\Theta(\log(n))$ | $\Theta(\log(n))$ | -| Halda | $\Theta(\log(n))$ | N/A | N/A | $\Theta(1)$ | $\Theta(\log(n))$ | + - paměťová: $\Theta(1)$ \ No newline at end of file diff --git a/KIV PPA2/16. Rekapitulace ADT.md b/KIV PPA2/16. Rekapitulace ADT.md new file mode 100644 index 0000000..2c23518 --- /dev/null +++ b/KIV PPA2/16. Rekapitulace ADT.md @@ -0,0 +1,16 @@ +# Rekapitulace ADT + +**Přístup k datům pomocí indexů** + +| | vybrání | odebrání | přidání | +| ----------------- | ----------- | ---------------------------- | ---------------------------- | +| spojová struktura | $\Theta(n)$ | $\Theta(1)$ pokud byl vybrán | $\Theta(1)$ pokud byl vybrán | +| dynamické pole | $\Theta(1)$ | $\Theta(n)$ | $\Theta(n)$ | + +**Přístup k datům pomocí klíče** + +| | přidání | odebrání | vybrání | vybrání maxima | odebrání maxima | +| ------- | ----------------- | ----------------- | ----------------- | ----------------- | ----------------- | +| Tabulka | $\Theta(1)$ | $\Theta(1)$ | $\Theta(1)$ | $\Theta(n)$ | $\Theta(n)$ | +| BST | $\Theta(\log(n))$ | $\Theta(\log(n))$ | $\Theta(\log(n))$ | $\Theta(\log(n))$ | $\Theta(\log(n))$ | +| Halda | $\Theta(\log(n))$ | N/A | N/A | $\Theta(1)$ | $\Theta(\log(n))$ | diff --git a/KIV PPA2/Prednaska13.md b/KIV PPA2/17. Vypočítatelnost, složitost problémů.md similarity index 100% rename from KIV PPA2/Prednaska13.md rename to KIV PPA2/17. Vypočítatelnost, složitost problémů.md diff --git a/KIV PPA2/Prednaska06.md b/KIV PPA2/Prednaska06.md deleted file mode 100644 index 750c0bd..0000000 --- a/KIV PPA2/Prednaska06.md +++ /dev/null @@ -1,120 +0,0 @@ -# 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` - - 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` - - pokud potřebujeme použít nějakou metodu tohoto rozhraní ve třídě, můžeme `Object` přetypovat na `T` \ No newline at end of file diff --git a/KIV PPA2/Prednaska11.md b/KIV PPA2/Prednaska11.md deleted file mode 100644 index 9c117a6..0000000 --- a/KIV PPA2/Prednaska11.md +++ /dev/null @@ -1,57 +0,0 @@ -# Grafy 2 - -#### Prohledávání do šířky (BFS) - -**Strom dosažitelnosti** -- tvoří se z nějakého určeného vrcholu (kořen) -- ukazuje, jaká je nejkratší cesta do ostatních vrcholů -- reprezentován polem, kde na indexu vrcholu je uložen předek -- nemusí být jednoznačný (může existovat více nejkratších cest) - - -#### Prohledávánı́ do hloubky (DFS) - -- Depth-First Search -- algoritmus postupuje do většı́ vzdálenosti od počátečnı́ho vrcholu, pokud může -+ předpokládáme, že označenı́ (mark) je před volánı́m DFS inicializováno na 0 pro všechny vrcholy -+ DFS je potřeba doplnit o nějaký užitečný kód - + záleží to na řešeném problému - -**Značenı́ vrcholů** -- nezpracovaný (”bı́lá”), kód 0 -- rozpracovaný (”šedá”), kód 1 -- dokončený (”černá”), kód 2 - -**Složitost** -- rekurzivní metoda se pro každý vrchol volá pouze jednou - $\Omega(\vert V\vert)$ -- pro každý vrchol se prochází seznam hran: - - reprezentace maticí - $\Omega(\vert V\vert^2)$ - - reprezentace seznamem - $\mathcal{O}(\vert E\vert)$ -- celkem: $\mathcal{O}(\vert V\vert + \vert E\vert)$ při reprezentaci seznamem - - může být i $\Omega(\vert V\vert^2)$, pokud $\vert E\vert = k\vert V\vert^2$ - -**Použití DFS** -- Zjištění dosažitelnosti vrcholu - - pokud předpokládáme, že bude vrchol daleko, je DFS vhodnější než BFS -+ Zjištění cyklu v grafu - + vrchol označíme jedničkou a poté ho znovu hledáme -+ Topologické řazení - + prvně je potřeba ověřit, že graf nemá cykly - + vrcholy jsou činnosti, hrany jsou závislosti - + hrana $A \to B$ značí, že se prvně musí vykonat A a potom až B - + pomocí DFS můžeme snadno určit pořadí činností (pomocí otočeného grafu) - -**DFS bez rekurze** -- pravděpodobně nastanou problémy s hloubkou zásobníku -+ vystačíme si se zásobníkem celých čísel (vrcholů) -+ `segment` (jaký je stav vrcholu) je v označení vrcholu (`mark`) - -**Nejkratší cesta v ohodnoceném grafu** -- velmi častý problém -- ohodnocení: čas, vzdálenost, ... -- úkol: nalézt nejkratší vzdálenost ke všem vrcholům -- **Dijkstrův algoritmus** - - je potřeba prioritní fronta - - přidání dvojice vrchol + ohodnocení - - vybrání/odebrání vrcholu s nejmenším ohodnocením - - změna ohodnocení vrcholu \ No newline at end of file