Roztřídění poznámek z PPA2 podle témat
This commit is contained in:
parent
247b469959
commit
b8eb3580e7
|
@ -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é
|
||||
- ...
|
24
KIV PPA2/02. Rekurzivní programy.md
Normal file
24
KIV PPA2/02. Rekurzivní programy.md
Normal file
|
@ -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é
|
|
@ -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čů
|
|
@ -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
|
25
KIV PPA2/05. Abstraktní datové typy.md
Normal file
25
KIV PPA2/05. Abstraktní datové typy.md
Normal file
|
@ -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í)
|
|
@ -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
|
||||
|
45
KIV PPA2/07. Odstranění rekurze.md
Normal file
45
KIV PPA2/07. Odstranění rekurze.md
Normal file
|
@ -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
|
42
KIV PPA2/08. ADT Fronta.md
Normal file
42
KIV PPA2/08. ADT Fronta.md
Normal file
|
@ -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)$
|
34
KIV PPA2/09. Třídy s typovým parametrem.md
Normal file
34
KIV PPA2/09. Třídy s typovým parametrem.md
Normal file
|
@ -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<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`
|
|
@ -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<T>`
|
||||
|
||||
- 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<T> iterator()`
|
||||
- `ListIterator<T> listIterator()` - lepší iterátor
|
||||
|
||||
### Třída `ArrayList<T>`
|
||||
|
||||
- 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<T>`
|
||||
|
||||
**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<T>`**
|
||||
- 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<T>`
|
||||
|
||||
- rozhraní fronty
|
||||
- `LinkedList<T>` toto rozhraní implementuje
|
||||
|
||||
**Operace**
|
||||
- `void add()`
|
||||
- `T element()`
|
||||
- `T remove()`
|
||||
|
||||
### Třída `Stack<T>`
|
||||
|
||||
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)$.
|
||||
- index aktuálního prvku `current`
|
79
KIV PPA2/11. Kolekce v Javě.md
Normal file
79
KIV PPA2/11. Kolekce v Javě.md
Normal file
|
@ -0,0 +1,79 @@
|
|||
# Kolekce v Javě
|
||||
|
||||
Java poskytuje knihovní třídy pro základní implementaci kolekcí
|
||||
|
||||
### Třída `LinkedList<T>`
|
||||
|
||||
- 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<T> iterator()`
|
||||
- `ListIterator<T> listIterator()` - lepší iterátor
|
||||
|
||||
### Třída `ArrayList<T>`
|
||||
|
||||
- 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<T>`
|
||||
|
||||
**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<T>`**
|
||||
- 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<T>`
|
||||
|
||||
- rozhraní fronty
|
||||
- `LinkedList<T>` toto rozhraní implementuje
|
||||
|
||||
**Operace**
|
||||
- `void add()`
|
||||
- `T element()`
|
||||
- `T remove()`
|
||||
|
||||
### Třída `Stack<T>`
|
||||
|
||||
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)$.
|
|
@ -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)$
|
|
@ -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íčů
|
|
@ -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$
|
||||
+ 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
|
|
@ -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)$
|
16
KIV PPA2/16. Rekapitulace ADT.md
Normal file
16
KIV PPA2/16. Rekapitulace ADT.md
Normal file
|
@ -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))$ |
|
|
@ -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<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`
|
|
@ -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
|
Loading…
Reference in a new issue