# 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` - 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)$.