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

This commit is contained in:
Filip Znachor 2023-03-30 22:23:32 +02:00
parent 9c86d331ab
commit f159f4e022
1 changed files with 158 additions and 0 deletions

158
KIV PPA2/Prednaska07.md Normal file
View File

@ -0,0 +1,158 @@
# Seznam
- abstraktní datová struktura
- umožňuje vložení i odebrání prvku z jakékoliv pozice
Jak specifikovat pozici?
- indexem
- aktuální pozice
### Ukazovátko
- ukazuje na aktuální pozici v seznamu
- posun dopředu i na začátek
- operace v $\Theta(1)$
- **možné interpretace**:
- 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
- vybírání/odebírání dohodou - třeba prvek napravo
### Implementace spojovou strukturou
- opět spojovací dílek - data a následující prvek
- reference na první (`first`) a aktuální prvek (`current`)
- ukazovátko míří na `current` a `current.next`
- je-li `current = null`, míří se před první prvek seznamu
- **pohyb ukazovátka**:
- `moveToFirst` - na začátek
- `next` - na další prvek
- potřeba myslet na posun z `null` a neexistující další prvek
- **přidávání** mezi dva prvky:
- přepíše se odkaz `current.next` na vložený prvek
- vloženému prvku se nastaví původní `current.next`
- **mazání** prvku
- vyřešení speciálních případů (na začátku, na konci)
- `current.next = current.next.next`, prvek se přeskočí
- **vybrání** prvku na zadané pozici
- projdeme seznam od začátku
- $\Omega(n)$ složitost!
### Iterátor
- 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
- stejná implementace jako u seznamu (místo `first` se použije `list.first`)`
**Operace**
- vybrání dat napravo (`get()`)
- posunutí doprava (`next()`)
- vrácení na začátek (`moveToFirst()`)
- přidání prvku na pozici (`insert(...)`)
- odstranění prvku napravo (`remove()`)
- vytvoření klonu (`clone()`), který ukazuje na stejný prvek
**Problémy**
- iterátory o sobě nevědí
- jeden smaže prvek, na který odkazuje jiný iterátor
- řešení
- používat více iterátorů pouze pro čtení
- při editaci zajistit, aby nebyl zasažen jiný iterátor
- pohyb pouze dopředu
- řešení: obousměrně zřetězený seznam
- spojovací prvek s `next` i `previous `
- v iterátoru nová metoda `previous()`
- složitější konzistence struktury
- 2x více režijní paměti
### Implementace paralelními poli
- jen dopředné zřetězení
- dvě stejně dlouhá pole
- pro data
- 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)$.