Obsah
Cvičení z algoritmů a datových struktur I 2015/16
Na pravé straně této stránky vizte obsah. Silně doporučuji pečlivě vše pročíst.
Při emailové komunikaci se mnou prosím vždy uveďte do předmětu text [ADS1_2016]
. Pozor: pokud mi chcete psát cokoliv nesouvisejícího s domácími úlohami (organizační dotaz, žádost o konzultaci, poznámka ke cvičení, …), napište mi zvláštní email a do předmětu uveďte [ADS1_2016][!DU]
. Pokud to neuděláte, mail může na delší dobu zapadnout mezi domácí úkoly. Díky.
Paralelní cvičení učí Jan Musílek, Jan Bok, Jirka Setnička a Radek Hušek, na jejichž webech se můžete inspirovat. Účast na cvičení není povinná.
Co se dělalo na cvičení
Co se (údajně) dělalo na přednášce
- 6. přednáška
- quicksort je velmi podobný jako vkládání prvků do BVS
- B-stromy (jak vypadají, insert, delete)
- úvod do třídících algoritmů (časová složitost bubble sortu, merge sortu a quicksortu)
- 7. přednáška
- znovu B-stromy
- halda (k čemu je + operace hledání min, sjednocení dvou hald, insert, delete)
- opět třídění (jak průměrně funguje bubble sort, quick sort, merge sort; důkaz toho, že když máme jakýkoli algoritmus, který třídí na základě porovnávání prvků, tak musí provést alespoň $O(n \log n)$ porovnání –> důsledek: nemůžeme vymyslet třídící algoritmus, kterému stačí méně než $\log_2 n$ operací pro jeden prvek)
- 8. přednáška
- detailně důkaz dolního odhadu třídích algoritmů (zde)
- radix sort (popis a ukázka toho, že pokud máme nějakou přiměřenou množinu malých čísel, tak algoritmus tohoto sortu beží v $O(n)$)
- 9. přednáška
- pokračování radix sort (změna oproti minulé přednášce - závěrečný for cyklus pozpátku, abychom měli stabilní uspořádání, tj. uspořádání, kde prvky se stejným klíčem budou po setřídění ve stejném pořadí jako před tříděním; zmínka o třídění stabilním tříděním pozpátku - odzadu podle poslední cifry)
- hashování (základní popis, co říká (bez důkazu) (zde)
- implementace hashování (otevřené hashování = hashovací pole minimálně 2x větší než počet prvků, pokud by více prvků hashovací funkce namířila do jednoho políčka v hashovacícm poli, tak ho uložíme do nejblížšího volného políčka napravo, v hashovací tabulce vyhledáváme standardně, ale musíme se koukat i na prvky napravo od místa, kam nás poslala hash funkce, dokud nenarazíme na mezeru nebo hledané číslo –> implementace se hodí jen pro ukládání a vyhledávání - pokud v ní začneme mazat, nesmíme místo mazaného prvku nechat volné políčko, protože by se mohlo stát, že nějaké prvky už při hledání nikdy nenalezneme)
- 10. přednáška
- univerzální hashování (kde počet prvku universa je prvočíslo)
- perfektní hashování (snaha vyhnout se kolizím – máme k dispozici více hashovacích funkcí a vybíráme si tu, která danou podmnožinu množiny universa zobrazí bez kolizí)
Domácí úkoly
Úloha inverze (6b, plný počet do 14. 3.)
Navrhněte algoritmus, který spočte počet inverzí zadané permutace p, tedy „dvojic ve špatném pořadí“: $\{(a,b)|a<b,p(a)>p(b)\}$.
Úloha unikum (6b, plný počet do 14. 3.)
Najděte v posloupnosti nejdelší úsek, v němž se žádná hodnota neopakuje.
Úloha medián (8b, plný počet do 14. 3.)
Jak v lepším než lineárním čase najít medián sjednocení dvou setříděných posloupností?
Vstup je zadán jako už načtená pole jen ke čtení, nebo alternativně jako orakulum (funkce), které umí vrátit $i$-tý prvek z dané vstupní posloupnosti.
Hint: Hledejte rekurzivně $k$-tý nejmenší ze dvou podposloupností.
Úloha rovnováha (9b, plný počet do 28. 3.)
Vymyslete algoritmus, který v lineárním čase přebuduje vyhledávací strom na dokonale vyvážený. Nemáte dost paměti na to, abyste si mohli pořídit ještě jednu kopii prvků – kromě stromu si smíte pamatovat $O(1)$ hodnot (pointerů, počitadel do $n$, kopií hodnot).
Úloha merge (10b, plný počet do 28. 3.)
Navrhněte algoritmus pro sloučení dvou AVL stromů $A$ a $B$, kde všechny prvky $A$ leží před všemi prvky $B$, do jediného AVL stromu $C$. Hledáme řešení s lepší složitostí než $O(min(|A|,|B|))$.
Úloha datovka-2 (8b, plný počet do 18. 4.) Elektrikář si chce udržovat seznam klientů podle jejich identifikačních čísel (ID) a s údajem, zda se jedná o muže či ženu. Navrhněte datovku, která bude umět následující operace v $O(\log n)$:
INSERT(K,C)
— vloží nového klient $C$ s ID=$K$, označí ho jako ženuUPDATE(K)
— klienta s ID $K$ přeznačí na mužeFINDDIFF(K)
— spočítej rozdíl počtu mužů a žen mezi klienty s ID $\leq K$.
Úloha min-strom (8b, plný počet do 25. 4.)
Minimový binární strom $M(a)$ pro zadanou posloupnost $a=(a_1\dots a_n)$ bez opakujících se prvků je definován takto:
Buď $a_i$ minimální prvek $a=(a_1\dots a_n)$; pak kořen $M(a)$ je $a_i$, jeho levý podstrom je $M(a_1\dots a_{i-1})$ a pravý podstrom $M(a_{i+1}\dots a_n)$. $M(\emptyset)$ je prázdný strom.
Pro zadanou posloupnost postavte minimový strom v čase $O(n)$.
Úloha tridena-majorita (5+5b, plný počet do 25. 4.)
Majorita posloupnosti je prvek, který se v ní vyskytuje na více než polovině pozic (posloupnost tedy má jednu nebo žádnou majoritu). Na cvičení ukážeme (ukázali jsme) příklad, kdy je úkolem najít majoritu, pokud existuje, s pamětí $O(1)$ (resp. $O(\log n)$ na RAMu) v čase $O(n)$.
Pokud je posloupnost setříděná, lze zda má majoritu zjistit a zároveň ji najít mnohem rychleji, a to v čase $O(\log n)$. Popište takový algoritmus.
Pro 5 bodů navíc dokažte, že rychleji toto není možné zjistit. Pro plný počet by tento důkaz měl být jasný a úplný.
Úloha housenka (9b, plný počet do 2. 5.) Najděte v zadaném stromě housenku na co nejvíce vrcholech. Housenka je podgraf, který se skládá z cesty na jejímž každém vrcholu jsou až čtyři listy (nožičky), ale můžou tam být i vrcholy bez nožiček. Není to totéž, co nejdelší cesta, protože nejde o housenku co nejdelší, ale na největším počtu vrcholů (tedy i s nožičkami). Řešení by mělo být v $O(n)$.
Úloha kůň (8b, plný počet do 2. 5.) Na jedné šachovnici $N\times N$ žil byl kulhavý kůň. To je je šachová figurka, která v sudém tahu táhne jako jezdec, v lichém jako pěšec (o 1 dopředu, vždy stejným směrem). Jak pro zadaná dvě políčka najít nejkratší cestu kulhavým koněm?
Úloha zakázka (10b, plný počet do 11. 5.)
Olga Opatrná najala Láďu Lenocha, aby ji pro daný neorientovaný graf $G=(V,E)$, vrchol $s\in V$ a nezáporné celočíselné váhy hran $w(u,v)$ (kde $w(u,v)=w(v,u)$) spočítal nejkratší cesty z vrcholu $s$ do všech ostatních vrcholů. Konkrétně má Láďa spočíst dvě funkce: $d(v)$ má být délka nejkratší cesty z $s$ do $v$ (nebo $\infty$, pokud taková není), a $\pi(v)$ má být předposlední vrchol na nějaké nejkratší cestě z $s$ do $v$ (nebo $\mathrm{NIL}$, pokud taková není).
Olga ale moc nevěří Láďově pečlivosti, a tak si chce výsledky ověřit, což se jí zdá jednodušší, než si je spočíst sama. Konkrétně ověří následující podmínky:
- $d(s)=0$
- $\pi(s)=\mathrm{NIL}$
- $\forall (u,v)\in E: d(v) \leq d(u) + w(u, v)$
- $\forall v\in V: \pi(v)\neq\mathrm{NIL}\Rightarrow d(v) = d(\pi(v)) + w(\pi(v),v)$
- $\forall v\in V, v\neq s: d(v) < \infty \Rightarrow \pi(v) \neq\mathrm{NIL}$
Jak může Láďa Olze dát data $d$ a $\pi$, která nejsou korektní podle Olžina zadání, ale splňují tyto ověřovací podmínky? Konkrétně: najděte takový graf, funkci $w$, vrchol $s$ a funkce $d$ a $\pi$, nebo ještě lépe popište takové případy obecněji. Za druhé upravte či doplňte podmínky tak, aby už každé řešení splňující tyto podmínky popisovalo nejkratší vzdálenosti a cesty.
Úloha abeceda (9b, plný počet do 11. 5.) Nalezli jste knihovnu ztracené civilizace a zkoumáte její abecedu o $n$ prapodivných znacích. Každá kniha má na svém hřbetu nápis touto abecedou a doufáte, že jsou knihy seřazené abecedně (lexikograficky). Rádi byste věděli, jestli z pořadí knížek lze zjistit jednoznačné pořadí znaků abecedy, jestli je pro to informací málo, či zda dokonce takové pořadí nemůže existovat (a knihovnu tedy někdo přeházel).
Zadání si představte třeba jako seznam slov bez mezer z abecedy „a-z“, otázkou je pak pořadí znaků „a-z“ v hledané abecedě. Zkuste najít algoritmus, který to zvládne v lineárním čase s velikostí vstupu. Můžete předpokládat, že se každé písmeno mezi nápisy vyskytne.
Úloha polosouvislost (9b, plný počet do 30. 5.)
Řekněme, že orientovaný graf $G$ je polosouvislý, když pro každé dva vrcholy $u$ a $v$ platí, že existuje orientovaná cesta z $u$ do $v$ nebo orientovaná cesta z $v$ do $u$. Toto je silnější vlastnost, než slabá souvislost grafu, ale slabší vlastnost, než silná souvislost grafu. Jak v čase $O(m+n)$ zjistit, zda je $G$ polosouvislý?
Úloha holubi (9b, plný počet do 30. 5.) Každý poštovní holub, je-li vypuštěn se zprávou, s ní doletí jen na jedno místo, které je pro konkrétního holuba pevné. Ve spolku pěstitelů holubů má každý člen holuby, kteří mohou doručit zprávu k několika dalším členům. Svolat všepěstitelské setkání je možné jen tak, že ho jeden ze členů vyhlásí rozesláním zpráv všem členům, na které má holuby, a ti pak pošlou zprávu dál svými holuby.
Když znáte strukturu spolku, v čase lineárním s počtem zúčastněných holubů a členů zjistěte, zda vůbec existuje někdo, kdo má možnost setkání všech členů svolat.
Úloha cheating (7b, plný počet do 30. 5.)
Závod bludištěm z živých plotů! Jste rozhodnuti vyhrát a to i za cenu malé … zkratky, kterou pravidla zapomněla zmínit. Nejste ale ochotni se křovím prodrat víc než jednou, ještě by si toho někdo všiml a mohl by to … špatně pochopit.
Bludiště je popsáno grafem se startem, cílem, délkami hran a dvěma typy hran; chodby bludištěm a zkratky křovím, kterými se ještě jde prodrat. Navrhněte algoritmus pro nejkratší cestu do cíle v co nejlepším čase.
Úloha listy-kostry (8b, plný počet do 30. 5.)
Máme dánu $U$ jako podmnožinu vrcholů souvislého grafu $G$ s váhami hran $w$. Najděte minimální kostru $G$ ze všech takových koster, které mají vrcholy z $U$ jako listy. Algoritmus by měl být stejně rychlý jako jiné vám známé algoritmy na min. kostru a měl by rozpoznat situaci, že taková kostra neexistuje.
Požadavky na zápočet
Zápočet je za zisk 100 bodů z domácích úloh, opravování úloh a za případný zápočtový programu či práci. Domácích úloh bude vypsáno za cca. 170 bodů. Váš aktuální počet bodů bude uveden v tabulce na konci této stránky. Pozor: z důvodu ochrany osobních údajů nemůžu bez vašeho svolení v tabulce uvádět vaše jméno; proto mi v každém řešení domácí úlohy uveďte i svou přezdívku, pod kterou chcete být v tabulce uvedeni. Pokud přezdívku neuvedete, beru to jako implicitní souhlas k uvedení vašeho skutečného jména. Na odevzdání za plný počet bodů máte 14 dní od zadání, finální termín odevzdání je konec výuky v letním semestru (konec května) krom několika posledních sérií.
K opravování úkolů: pokud jste při odevzdávání řešení domácího úkolu přesvědčeni, že jste úloze skutečně porozuměli a že vaše řešení je opravdu dobré, máte možnost získat navíc trojnásobek bodů tím, že se stanete korektorem pro tuto úlohu. (Např. když se stanete korektorem pro úlohu za 5b, dostanete navíc 15b.) Korektorem se můžete stát max. třikrát za semestr. Více o korektorství…
Domácí úlohy odevzdávejte emailem nejlépe jako čistý text či jako PDF. Neposílejte mi fotky ručně psaného textu, ale dobře nafocené obrázky jsou v pořádku. Pokud nechcete být uvedeni ve veřejné tabulce bodů či preferujete přezdívku (nechcete třeba být vyhledatelní), napište přezdívku ke každému vašemu řešení.
Zápočtová práce může mít podobu:
- programu implementující nějaký algoritmus z přednášky,
- teoretického rozboru algoritmu, který vás zaujme.
V prvním případě jde o implementaci nějaké varianty datové struktury či algoritmu z přednášky. Jazyk je omezen jen schopnostmi cvičícího (tedy [v pořadí preferencí] Python, Lua, Java, C#, hezké C, Pascal, Haskell, Lisp, Prolog,; na další se případně zeptejte), implementace musí být funkční a obsahovat krátký popis (co a jak je implementováno) a testovací data či testovací kód (knihovna tedy nemusí řešit načítání dat ze souboru a pod.). Za tento druh práce budu udělovat max. 30b, pokud se bude jednat o něco velmi jednoduchého, bodů bude méně. Zeptejte se předem, kolik lze za dané téma očekávat nejvýše bodů.
V druhém případě, tedy zejména pokud bude algoritmus či datová struktura složitější, bude práce jen teoretická, tzn. očekávám důkaz správnosti, rozbor složitosti a pseudokód. Za tento druh práce můžete očekávat do 40b, to zejména v případě, kdy si vyberete nějaký akademický článek a převyprávíte ho do mně (nezasvěcenému) srozumitelné podoby. Opět platí, že půjde-li o něco velmi jednoduchého, bodů bude méně. Zeptejte se předem, kolik lze za dané téma očekávat nejvýše bodů.
Termín na domluvení programu je do 15. června, termín odevzdání hotové verze pak konec června. Ostatní domácí úlohy mají až na výjimky termín do konce května.
Korektorství
Pokud jste při odevzdávání řešení domácího úkolu přesvědčeni, že jste úloze skutečně porozuměli a že vaše řešení je opravdu dobré, pošlete ho v emailu s předmětem začínajícím [ADS1_2016][korektor]
. Já vaše řešení zhodnotím a pokud bude opravdu v pořádku, za opravení řešení vašich kolegů dostanete trojnásobek bodové hodnoty příkladu. Korektorem se můžete stát nejvýše třikrát za semestr. Naopak pokud si vyloženě nepřejete, aby někdo z vašich kolegů vaše řešení (jakožto korektor) četl, tzn. přejete si, abych vaše řešení opravoval osobně, pošlete email s předmětem začínající [ADS1_2016][!korektor]
. Podotýkám ale, že se tak můžete připravit o často kvalitnější zpětnou vazbu, než vám dávám já.
Technicky to bude fungovat tak, že když mi od někoho přijde řešení dané DÚ, přepošlu ho příslušnému korektorovi. Korektor si řešení pečlivě přečte a zhodnotí ho. Je toto řešení korektní? Pokud ne, kde udělal autor chybu? Čemu nerozumí a jak mu můžu pomoci – jakou otázkou ho nakopnu správným směrem? Dále – je toto řešení přehledné a srozumitelné? Prospělo by řešení rozdělit do více/méně odstavců? Zavést nějaké značení? Atd. Na základě tohoto zhodnocení pak korektor navrhne bodové ohodnocení. Například:
Řešení je v zásadě správné, ale doporučil bych místo značení A, B, C, … používat indexované značení A_1, A_2, A_3, … Jinak byl důkaz poměrně přehledný.
4b
Tyto poznámky pak korektor pošle autoru úlohy a v kopii též mě. Já zhodnotím řešení úlohy a korekturu, případně se k oběma vyjádřím a pokud budu s hodnocením souhlasit, zapíšu do tabulky získané body.
Povinností korektora je opravit všechny zaslané úlohy do týdne od zaslání řešení.
Jak zápočťáky fungují
Zápočtová práce může mít podobu:
- programu implementující nějaký algoritmus z přednášky,
- teoretického rozboru algoritmu, který vás zaujme.
V prvním případě jde o implementaci nějaké varianty datové struktury či algoritmu z přednášky. Jazyk je omezen jen schopnostmi cvičícího (tedy [v pořadí preferencí] Python, Lua, Java, C#, hezké C, Pascal, Haskell, Lisp, Prolog,; na další se případně zeptejte), implementace musí být funkční a obsahovat krátký popis (co a jak je implementováno) a testovací data či testovací kód (knihovna tedy nemusí řešit načítání dat ze souboru a pod.). Za tento druh práce budu udělovat max. 30b, pokud se bude jednat o něco velmi jednoduchého, bodů bude méně. Zeptejte se předem, kolik lze za dané téma očekávat nejvýše bodů.
V druhém případě, tedy zejména pokud bude algoritmus či datová struktura složitější, bude práce jen teoretická, tzn. očekávám důkaz správnosti, rozbor složitosti a pseudokód. Za tento druh práce můžete očekávat do 40b, to zejména v případě, kdy si vyberete nějaký akademický článek a převyprávíte ho do mně (nezasvěcenému) srozumitelné podoby. Opět platí, že půjde-li o něco velmi jednoduchého, bodů bude méně. Zeptejte se předem, kolik lze za dané téma očekávat nejvýše bodů.
Termín na domluvení programu je do 15. června, termín odevzdání hotové verze pak konec června. Ostatní domácí úlohy mají až na výjimky termín do konce května.
Nápady na zápočťáky
Implementovat R-B-stromy a (2,4)-stromy a graficky ukazovat jejich korespondenci. Za prostou implementaci datové struktury dám 30b, pokud vytvoříte interaktivní aplikaci, ve které bude uživatel zadávat operace na stromech a aplikace bude zobrazovat změny datových struktur a jejich korespondenci, dám 40b. Zcela ideální platformou by byl (kvůli přístupnosti) Javascript nebo cokoliv webového; přijmu to ale i v jakémkoliv jiném (výše zmíněném) jazyce. Řešení Petra Mánka. Řešení Honzy Kytky.- Nedávno se objevil článek A Pedagogically Sound yet Efficient Deletion algorithm for Red-Black Trees: The Parity-Seeking Delete Algorithm, který tvrdí, že popisuje variantu RB stromů, která je k výuce vhodnější a v praxi efektivnější, než LLRB. Naimplementujte je a popište jejich funkci tak, aby to bylo srozumitelné i spolužákům.
- Shellsort je velice zajímavý třídící algoritmus. Je v jistém smyslu zkřížením bubblesortu a insertsortu, ale může mít lepší časovou složitost. Možností, co byste s ním mohli dělat, je několik:
Implementovat ho pro několik variant parametru mezery (Gap sequences) a porovnat jeho chování pro tyto parametry experimentálně.(Hotovo, github)- Nejlepší posloupnost mezer v průměrném případě je prý 1, 4, 10, 23, … (vizte poslední odstavec této podkapitoly); toto bylo zjištěno experimentálně. Ověřte správnost těchto výsledků pro co největší čísla (aktuálně je známo jen prvních osm členů této posloupnosti, kdybyste přišli na devátý, dostanete celý zápočet ;). Pokud byste si vybrali toto témai, jistě by nebylo těžké vám zařídit přístup k výpočetní kapacitě fakulty.)
- Co kdyby se měl Shellsort přednášet? Sestavte co nejzajímavěji materiál k výkladu na hodinu a půl (jako přednáška z ADS), kde se ukáže princip fungování tohoto sortu a pak dokáže několik (jednodušších) odhadů na časovou složitost pro různé hodnoty parametru mezery. Nejvhodnějším médiem by byl IPython notebook (rád předvedu, jak funguje), protože do něj lze psát matematickou notaci i kód a interaktivně vše zkoušet.
- Splay tree je velice zajímavá datová struktura. Jedná se o binární vyhledávací strom, který se přizpůsobuje dotazům, které na něj přichází – pokud přichází mnoho dotazů na tytéž prvky, strom je vynese blízko ke kořeni, aby se k nim dalo přistupovat rychle. Samozřejmě má i svoje nevýhody. Implementujte ho a napište k němu několik generátorů posloupnosti operací, které budou demonstrovat, v čem je Splay strom lepší než jiné stromy (AVL, R-B, …) a kde naopak selhává. (Generátorem posloupnosti operací myslím nějakou funkci, které řeknu, kolik operací INSERT/FIND/DELETE chci na stromu udělat [třeba za účelem testování] a on mi je vygeneruje.)
- Implementujte Rabinův-Karpův algoritmus na vyhledávání podřetězce v řetězci pomocí hashování.
- Implementujte kterýkoliv exponenciální algoritmus z přednáškových poznámek Jeffa Ericksona a pochopte důkaz správnosti a časové/prostorové složitosti dostatečně, abyste mi ho uměli vysvětlit na tabuli.
- Implementujte algoritmus, který najde modulární rozklad grafu v lineárním čase dle článku Linear-time modular decomposition of directed graphs. Pokud úkol splníte, dám za něj 45b (+5b za prezentaci); i pokud se vám to nepodaří úplně, nebude bodová odměna malá. (Potenciálně je to taky dobrý základ pro ročníkový projekt nebo bakalářskou práci do příštích let.)
Hotové
- Samuel Slavkovský napsal porovnávač třídících algoritmů (rar s .net kódem), který doporučuji ke shlédnutí :)
- Úkoly ze cvika na Dijkstrův algoritmus. Vypracoval Tomáš Pavlín.
- Implementovat shellsort pro několik variant parametru mezery (Gap sequences) a porovnat jeho chování pro tyto parametry experimentálně. (Hotovo, github)
Články k rozebrání
Obecně je dobrým zdrojem konference SOSA, která se soustřeďuje na *hezké* (jednoduché) algoritmy, ačkoliv i tak mohou být přístupné spíš magisterským studentům.
- Hledání modulárního rozkladu grafu v lineárním čase, Linear-time modular decomposition of directed graphs
Články k rozebrání
[Časem budu doplňovat.]