Jméno:……………………….….. St. Sk.:……. Cvičící:………..………Bodů ze cv.:…… (Tučná čísla indikují počet neuspěvších (z 50) v jednotlivých otázkách) 1. 36 Heap sort a) b) c) d) e)
není stabilní, protože halda (=heap) není stabilní datová struktura není stabilní, protože žádný rychlý algoritmus ( Θ(n*log(n))) nemůže být stabilní je stabilní, protože halda (=heap) je vyvážený strom je stabilní, protože to zaručuje pravidlo haldy neplatí o něm ani jedno předchozí tvrzení
Heap sort není stabilní, c) i d) odpadají. b) není pravda, neboť Merge sort má dotyčnou rychlost a stabilní být může (většinou je). Dělení na stabilní a nestabilní a u datových struktur neexistuje (co by to vůbec bylo?), takže ani a) neplatí a zbývá jen e). Poznámka: Zde bychom ocenili zpětnou vazbu, proč se množství respondentů (35 !!) zdála „nestabilní datová struktura“ tak přítažlivá.
9 2. Funkce int ff(int x, int y) { if (x < y) return ff(x+1,y); return x; } a) b) c) d) e)
buď hned vrátí první parametr nebo jen „do nekonečna“ volá sama sebe vrátí maximální hodnotu z obou parametrů vrátí součet svých parametrů vrátí x+1 neprovede ani jednu z předchozích možností
Když je x větším (nebo stejným) z obou parametrů, jeho hodnota je vrácena ihned. V opačném případě se v rekurzivním volání jeho hodnota zvětšuje tak dlouho, dokud nedosáhne hodnoty y tedy původně většího z obou parametrů. Při návratu z rekurze již k žádným změnám nedochází, opět je tedy vrácena hodnota většího z obou parametrů. Platí možnost b). 0 3. Obsah uzlů daného stromu vypíšeme v pořadí postorder. Vznikne posloupnost a) b) c) d)
GFEDCBA FCGDBEA GCFAEBD DEBFGCA
Přímo z definice pořadí postorder plyne, že je nutno volit odpověď d).
4. 9 Metoda hashování s vnějším zřetězením a) nemá problém s kolizemi, protože při ní nevznikají
PDF vytvořeno zkušební verzí pdfFactory www.fineprint.cz
b) dokáže uložit pouze předem známý počet klíčů c) ukládá synonyma do samostatných seznamů v dynamické paměti d) ukládá synonyma spolu s ostatními klíči v poli Každý alespoň elementární popis zřetězeného rozptylování vede na odpověď b). Kolize vznikají vždy, pole se tu nepoužívá a počet klíčů není teoreticky omezen. 5. 20 V určitém problému je velikost zpracovávaného pole s daty rovna rovna 3n2·log(n2) kde n charakterizuje velikost problému. Pole se řadí pomocí Insert sort-u. Asymptotická složitost tohoto algoritmu nad uvedeným polem je tedy a) b) c) d) e)
Ο(n2 ·log(n)) Ο(n2 ·log(n2)) Ο(n4 ·log2(n)) Ο(n2 ·log(n) + n2) Ο(n2)
Máme-li velikost pole rovnu k, Insert sort jej zpracuje v čase Ο(k2). Velikost našeho pole je k = 3n2·log(n2), takže bude zpracováno v čase Ο(k2) = Ο((3n2·log(n2))2) = = O(9n4·log2(n2)) = O(9n4·4·log2(n)) = O(n4·log2(n)). Platí tedy možnost c). 6. 4 Uvedený konečný automat se startovním stavem S přijme slovo a) b) c) d) e)
aaaa ba bab bbb žádné z předchozích
Slovo bab je to pravé. Posloupnost přechodů je tato: (S), b --> (B), b --> (A), b --> (B). (B) je koncový stav, takže slovo bab je přijato. Žádné jiné slovo z nabízených přijato nebude, takže platí možnost c). Poznámka: Redakčním nedopatřením vznikly dva přechody ze stavu C označené písmenem b. Přechod ze stavu C po přečtení symbolu b je tedy nejednoznačný, naštěstí to však nemá na řešení celé otázky 6 žádný vliv. Objekt na obrázku kromě toho zůstává i nadále řádným konečným automatem, jen se stal nedeterministickým, ale o tom až v dalších semestrech...
7. 10 Datový typ a) je plně popsán soustavou axiomů b) je určen druhy dat a typickými operacemi c) je určen typickými operacemi d) je určen druhy dat
PDF vytvořeno zkušební verzí pdfFactory www.fineprint.cz
To je otázka pamatování si definice. Pro datový typ musí být známo, s jakými vůbec hodnotami může pracovat (= druhy dat) a také musí být známo, jaké operace nad těmito hodnotami lze v rámci datového typu provádět (= typické operace). Platí b). 8. 7 Levá rotace v uzlu u a) v podstromu s kořenem u přemístí pravého syna up uzlu u do kořene. Přitom se uzel u stane levým synem uzlu up a levý podstrom uzlu up se stane pravým podstromem uzlu u b) v podstromu s kořenem u přemístí levého syna ul uzlu u do kořene. Přitom se uzel u stane pravým synem uzlu ul a levý podstrom uzlu ul se stane pravým podstromem uzlu u c) v podstromu s kořenem u přemístí pravého syna up uzlu u do kořene. Přitom se uzel u stane levým synem uzlu up a pravý podstrom uzlu up se stane levým podstromem uzlu u d) v podstromu s kořenem u přemístí levého syna ul uzlu u do kořene. Přitom se uzel u stane pravým synem uzlu ul a pravý podstrom uzlu ul se stane levým podstromem uzlu u Zde můžeme jen doporučit nakreslení obrázku, případně nahlédnutí do vhodné publikace, možnost a) se ukáže být jedinou správnou. 9. 33 Vyvážení BVS některou z operací rotace a) b) c) d) e)
je nutno provést po každé operaci Insert je nutno provést po každé operaci Delete je nutno provést po každé operaci Insert i Delete snižuje hloubku stromu není pro udržování BVS nezbytné
Binární vyhledávací stromy se vyvažovat mohou a také nemusí. Možnosti a) b) c) tedy opadají a zřejmě platí možnost e). Možnost d) neplatí, protože rotace nemusí snížit hloubku stromu, je-li provedena dostatečně vysoko ve stromu v některé z kratších větví (jednoduché cvičení – najděte na to příklad, budete potřebovat pět pater stromu). 10. 20 V následující datové struktuře lze maximálně třemi operacemi přečíst poslední prvek a) b) c) d) e)
fronta zásobník tabulka strom žádná z uvedených
V tabulce ani ve stromu žádný poslední prvek definován není, možnosti c) a d) odpadají. Poslední prvek ve frontě obsahující alespoň pět prvky se na začátek dostane po nejméně čtyřech operacích Delete a žádný jiný přístup k němu není, takže možnost a) odpadá také. V zásobníku je naopak poslední prvek na vrcholu, takže je pomocí operací Pop či Top snadno přístupný i ke čtení. Platí možnost b)
PDF vytvořeno zkušební verzí pdfFactory www.fineprint.cz
Jméno:……………………….….. St. Sk.:……. Cvičící:………..………Bodů ze cv.:…… (Tučná čísla indikují počet neuspěvších (z 45) v jednotlivých otázkách) 1.
13 Merge sort a) b) c) d) e)
lze napsat tak, aby nebyl stabilní je stabilní, protože jeho složitost je Θ (n*log(n)) je nestabilní, protože jeho složitost je Θ(n*log(n)) je rychlý ( Θ(n*log(n))) právě proto, že je stabilní neplatí o něm ani jedno předchozí tvrzení
Rychlost a stabilita řazení nejsou v žádné příčinné souvislosti, odpovědi b), c), d) jsou pouhá „mlha“. Při slévání (vemte si k ruce kód!) můžeme jednoduchou záměnou ostré a neostré nerovnosti v porovnávání prvků způsobit, že při stejných porovnávaných prvcích dostane přednost buď prvek z levé nebo z pravé části řazeného úseku. Když dostanou přednost prvky z pravé části, octnou se nakonec v seřazeném poli před těmi prvky, které byly v levé části a měly stejnou hodnotu. To je ovšem projev nestability. Platí možnost a).
5 2. Funkce int ff(int x, int y) { if (y>0) return ff(x, y-1)+1; return x; } a) b) c) d) e)
sečte x a y, je-li y nezáporné pro kladná y vrátí y, jinak vrátí x spočte rozdíl x–y, je-li y nezáporné spočte rozdíl y–x, je-li y nezáporné vrátí hodnotu svého většího parametru
Pro y záporné nebo nulové vrátí fukce hodnotu x, Pro kladné y volá sama sebe. Počet volání je roven hodnotě y (neboť tento parametr se při každém volání o jedničku zmenší) a při návratu z rekurze se návratová hodnota z většuje pkaždé o 1. Počet volání je y, nejvnitřnější volání vrátí hodnotu x, takže návrat z rekurze přičte k x ještě hodnotu y. Správná odpověď je a).
2 3. Obsah uzlů daného stromu vypíšeme v pořadí preorder. Vznikne posloupnost a) b) c) d)
ABCDEFGH DBEAFCG ABDECFG DEFGBCA
Přímo z definice pořadí postorder plyne, že je nutno volit odpověď c).
4. 17 Metoda otevřeného rozptylování
PDF vytvořeno zkušební verzí pdfFactory www.fineprint.cz
a) generuje vzájemně disjunktní řetězce synonym b) dokáže uložit pouze předem známý počet klíčů c) zamezuje vytváření dlouhých clusterů ukládáním synonym do samostatných seznamů v dynamické paměti d) dokáže uložit libovolný předem neznámý počet klíčů Varianty a), c), d) platí zřejmě pro zřetězené rozptylování, což vyplývá bezprostředně již z jakéhokoli jednoduchého popisu zřetězeného rozptylování. Zbývá jen správná možnost b). 5. 16 V určitém problému je velikost zpracovávaného pole s daty rovna rovna 2n3·log(n) kde n charakterizuje velikost problému. Pole se řadí pomocí Select sort-u. Asymptotická složitost tohoto algoritmu nad uvedeným polem je tedy a) b) c) d) e)
Θ(n2) Θ(n6 ·log2(n)) Θ(n3 ·log(n)) Θ(n3 ·log(n) + n2) Θ(n5 ·log(n))
Máme-li velikost pole rovnu k, Select sort jej zpracuje v čase Θ(k2). Velikost našeho pole je k = 2n3·log(n), takže bude zpracováno v čase Θ (k2) = Θ((2n3·log(n))2) = = Θ(4n6·log2(n)) = Θ(n6·log2(n)). Platí tedy možnost b). 6. 9 Uvedený konečný automat se startovním stavem S přijme slovo a) b) c) d) e)
babb ba aaa aba žádné z předchozích
Slovo aba je to pravé. Posloupnost přechodů je tato: (S), a --> (A), b --> (S), b --> (A). (A) je koncový stav, takže slovo aba je přijato. Žádné jiné slovo z nabízených přijato nebude, takže platí možnost d). 7. 6 Druh dat a) popisuje syntaxi datového typu b) popisuje sémantiku datového typu c) je povolená množina hodnot d) lze popsat graficky pomocí oválů, malých kroužků a spojovacích čar a písmen Toto je otázka směrem do definic – druh dat je to, co se zmiňuje ve variantě c).
PDF vytvořeno zkušební verzí pdfFactory www.fineprint.cz
8. 13 Pravá rotace v uzlu u a) v podstromu s kořenem u přemístí pravého syna up uzlu u do kořene. Přitom se uzel u stane levým synem uzlu up a levý podstrom uzlu up se stane pravým podstromem uzlu u b) v podstromu s kořenem u přemístí levého syna ul uzlu u do kořene. Přitom se uzel u stane pravým synem uzlu ul a levý podstrom uzlu ul se stane pravým podstromem uzlu u c) v podstromu s kořenem u přemístí pravého syna up uzlu u do kořene. Přitom se uzel u stane levým synem uzlu up a pravý podstrom uzlu up se stane levým podstromem uzlu u d) v podstromu s kořenem u přemístí levého syna ul uzlu u do kořene. Přitom se uzel u stane pravým synem uzlu ul a pravý podstrom uzlu ul se stane levým podstromem uzlu u Zde můžeme – stejně jako ve vedlejším oddělení – jen doporučit nakreslení obrázku, případně nahlédnutí do vhodné publikace, možnost d) se ukáže být jedinou správnou. 9. 17 Binární vyhledávací strom: a) musí splňovat podmínku haldy b) udržuje v každém uzlu referenci na uzel s nejbližším větším klíčem c) udržuje v každém uzlu referenci na uzel s nejbližším větším i s nejbližším menším klíčem d) po každém vložení prvku do BVS musí proběhnout vyvážení stromu e) po průchodu v pořadí inorder vydá seřazenou posloupnost klíčů Podmínku haldy musí splňovat pouze halda, která ani není BVS. Reference na jiné uzly než jen bezprostřední potomky nejsou v BVS povinností a vyvažování BVS také není povinné. Zbývá tak jen možnost e), o níž se hovoří i při výkladu pořadí inorder jako takového. 10. 27 Následující datová struktura má definován index a) b) c) d) e)
fronta tabulka strom množina žádná z uvedených
Ze základních ADT má index definováno jen pole. To se v nabízeném seznamu nevyskytuje, takže platí možnost e) – žádná z uvedených.
PDF vytvořeno zkušební verzí pdfFactory www.fineprint.cz
Jméno:……………………….….. St. Sk.:……. Cvičící:………..………Bodů ze cv.:……
1. (5 b.) Deklarujte uzel binárního stromu, který bude obsahovat celočíselné složky výška a hloubka. Ve složce hloubka bude uložena hloubka daného uzlu ve stromu, ve složce výška jeho výška. Výška uzlu X je definována jako vzdálenost od jeho nejvzdálenějšího potomka (= počet hran mezi uzlem X a jeho nejvzdálenějším potomkem). Napište funkci, která každému uzlu ve stromu přiřadí korektně hodnotu jeho hloubky a výšky. -------------------Při počítaní hloubky stačí každému potomku uzlu X přiřadit o 1 větší hloubku než má uzel X. Sama rekurzivní procedura mluví za dlouhé výklady: void setHloubka(node x, int depth) { if (x == null) return; x.hloubka = depth; setHloubka(x.left, depth+1); setHloubka(x.right,depth+1); } Přiřazení hloubky každému uzlu ve stromu pak provedeme příkazem setHloubka(ourTree.root, 0); Všimněte si, že hloubky se uzlům přiřazují – celkem logicky – v pořadí preorder. Při přiřazování výšky uzlu X musíme naopak znát výšku jeho potomků, takže se nabízí zpracování v pořadí postorder: void setVyska(node x) { int vyskaL = -1; // nejprve predpokladejme, ze uzel nema potomky. int vyskaR = -1; // dtto if (x.left != null) { setVyska(x.left); vyskaL = x.left.vyska; } if (x.right != null) { setVyska(x.right); vyskaR = x.right.vyska; } x.vyska = max(vyskaL, vyskaR) + 1; } Přiřazení výšky každému uzlu ve stromu pak provedeme příkazem if (ourTree.root != null) setVyska(ourTree.root);
Celý proces s výškou lze zachytit ještě úsporněji: int setVyska(node x) { if (x == null) return -1; x.vyska = 1+ max(setVyska(x.left), setVyska(x.right)); } Přiřazení výšky každému uzlu ve stromu pak provedeme např. příkazem zbytecnaProm = setVyska(ourTee.root);
PDF vytvořeno zkušební verzí pdfFactory www.fineprint.cz
2. (5 b.) Implementujte nerekurzivní variantu Merge sortu s využitím vlastního zásobníku. Vaše implementace nemusí usilovat o maximální rychlost, stačí, když dodrží asymptotickou složitost Merge sortu. Jednotlivé operace zásobníku neimplementujte, předpokládejte, že jsou hotovy, a pouze je vhodně volejte. Merge sort řeší svou úlohu pomocí procházení stromu rekurze v pořadí postorder. Je to zřejmé, protože k tomu, aby mohl být zpracován (=seřazen) některý úsek pole, musí být jïž seřazeny obě jeho poloviny, tj řazení muselo proběhnout v potomcích uzlu, který reprezentuje aktuální úsek. Musíme tedy umět zpracovat uzly stromu v pořadí postorder bez rekurze. Na zásobník si budeme ukládat jednotlivé uzly spolu s informací koikrát byly již navštíveny. Do zpracování uzlu se dáme až tehdy, když ze zásobníku vyzvedneme uzel s informací že do něho již vstupujeme potřetí (tj přicházíme z jeho již zpracovaného pravého podstromu). Průchod stromem může proto vypadat např. takto: if (ourTree.root == null) return; stack.init(); stack.push(ourTree.root, 1) while (stack.empty() == false) { (nodeX, time) = stack.pop(); if (isLeaf(nodeX) == true) continue; // Listy ve stromu merge sortu // budou úseky o délce jedna, // ty nijak zpracovávat (= řadit) nebudeme if( time == 1) { stack.push(nodeX, time+1); // počet návštěv akt. uzlu vzrostl stack.push(nodeX.left, 1) // a doleva jdeme poprvé } if( time == 2) { stack.push(nodeX, time+1); stack.push(nodeX.right, 1) } if( time == 3) { zpracuj(nodeX);
// počet návštěv akt. uzlu vzrostl // a doprava jdeme poprvé
// zpracování = sloučení úseku pole //odpovídajícího uzlu nodeX.
} } // end of while
Uvedenou kostru algoritmu je jen nutno doplnit: -- uzel stromu odpovídá řazenému úseku pole, nodeX tedy bude charakterizován a nahrazen dvojicí (horní mez, dolní mez) určující úsek pole. -- test isLeaf(nodeX) nahradíme testem, zda horní a dolní mez jsou si rovny -- vÿpočteme střed řazeného úseku. Levý následník pak bude charakterizován dvojicí čísel (dolní mez, střed), pravý následník dvojicí čísel (střed+1, horní mez) -- zpracuj (nodeX) nebude nic jiného, než obyčejné slévání obou polovičních úseků (dolní mez, střed) a (střed+1, horní mez) do úseku (dolní mez, horní mez) stejně jako je tomu v rekurzivním Merge sort-u. Budeme jen potřebovat pomocné pole pro slévání (to v rekurzivní variantě také potřebujeme). Slévání v nejjednodušší variantě sleje oba úseky do pomocného pole a odtud je zkopíruje zpět do řazeného pole.
PDF vytvořeno zkušební verzí pdfFactory www.fineprint.cz
3. (5 b.) Implementujte operace Init, Search, Insert pro rozptylovací tabulku s otevřeným rozptylováním, do níž se ukládají celočíselné klíče. Předpokládejte, že rozptylovací funkce je již implementována a Vám stačí ji jen volat. Použijte strategii „Linear probing“. Zde – pokud se nevyskytne přímá žádost – řešení prozatím neuvádím, jedná se jen o přímou implementaci standardní situace popsané v přednášce i literatuře, nic se tu nemusí „vymýšlet“, předpokládáme tedy, že si zájemci mohou (příp. s knihou či obrazovkou) tamtéž uvedené kódy projít.
PDF vytvořeno zkušební verzí pdfFactory www.fineprint.cz
Jméno:……………………….….. St. Sk.:……. Cvičící:………..………Bodů ze cv.:……
1. (5 b.) Na vstupu je neseřazené pole prvků pole[počet]. Bez toho, abyste toto pole seřadili, napište funkci, která v něm nalezne nalezne k-tý nejmenší prvek (= k-tý v seřazeném poli). Použijte metodu rozděl a panuj jako při řazení Quick-sortem, ale celé pole neřaďte. Hodnota k bude vstupním parametrem Vašeho algoritmu. Postup, který ve Quick sort-u dělí úsek pole na „malé“ a „velké“ hodnoty můžeme beze zbytku využít i zde. Dejme tomu, že máme pole prvků [1..n]. Nechť po rozdělení na „malé“ a „velké“ má poslední prvek v oddílu „malých“ index m. Nyní můžeme usuzovat takto: Pokud je k <= m, znamená to, že hledaný k-tý nejmenší prvek se nalézá mezi prvními (nejmenšími!!) m prvky v poli, čili jej budeme dále hledat pouze v úseku [1..m] a úsek [m+1..n] můžeme zcela zanedbat. Pokud naopak k > m, znamená to, že úsek [1..m] je zcela nezajímavý a hledat dále musíme již jen v úseku [m+1..n]. Ve vybraném úseku pak budeme dále tuto myšlenku aplikovat zcela identicky pomocí rekurze na čím dál menší úseky, tak dlouho, dokud nebude aktuální úsek obsahovat jen jeden prvek. To bude právě k-tý nejmenší prvek v celém poli. Postup dělení na „malé“ a „velké“ okopírujeme z Quick sort-u a umístíme pro přehlednost do jedné funkce, která vrátí hodnotu m, tj index posledního prvku v úseku „malých“ hodnot. int maxIndexSmall(int [ ] array, int Lo, int Hi); S využitím této funkce můžeme pak celý postup zapsat takto: int k_min (int [ ] array, int Lo, int Hi, int k) { if (Lo == Hi) return array[Lo]; int m = maxIndexSmall(array, Lo, Hi); if (k <= m) return k_min(array, Lo, m, k); if (k > m) return k_min(array, m+1, Hi, k); } Hledanou k-tou nejmenší hodnotu celého pole pak získáme příkazem k_nejm_hodnota = k_min(array, 1, n, k); Poznámka: Jo, jo, rekurze...
2. (5 b.) Implementujte cyklickou frontu v poli pole[délka]. Dokud není pole zcela naplněno, musí být fronta stále funkční, tzn. musí být možné do ní stále přidávat i z ní ubírat. Narazí-li konec nebo začátek fronty na konec nebo začátek pole, neposunujte všechny prvky v poli, zvolte výhodnější „cyklickou“ strategii, která zachová konstantní složitost operace Vlož a Vyjmi.
Myšlenka cyklické fronty je velmi jednoduchá. Připojíme první pozici pole ihned za poslední pozici a poslední pozici ihned před první. Tak se nám celé pole „zacyklí“ neboť při postupu stále doprava dojdeme nakonec na začátek pole. Nejsnáze se to implementuje pomocí indexů pole. Dejme tomu, že máme pole array[n]. int nextIndex(int i) { if (i < n-1) return (i+1); else return 0;
PDF vytvořeno zkušební verzí pdfFactory www.fineprint.cz
} int prevIndex(int i) { if (i > 0) return (i-1); else return (n-1); } Budeme-li pro pohyb v poli užívat pouze uvedené funkce, nemůžeme se dostat mimo meze pole. Protože se snadno stane, že po určité době života fronty se i při neprázdné frontě octne konec fronty před jejím začátkem v poli (namaluje si příslušný obrázek!), bude vhodné pro kontrolu prázdnosti či přeplnění fronty registrovat zvlášť počet prvků ve frontě Vložení prvku do fronty pak proběhne například takto: boolean insert(int key) { if (fronta.pocetPrvku == n) return false; fronta.konec = nextIndex(fronta.konec); array[fronta.konec] = key; fronta.pocetPrvku++; return true; } Obdobně bude implementována operace Delete, operace Init a Empty jsou již snad příliš jednoduché na to, aby tu musely být uvedeny.
3. (5 b.) Implementujte operace Init, Search, Insert a Delete pro rozptylovací tabulku se zřetězeným rozptylováním, do níž se ukládají celočíselné klíče. Předpokládejte, že rozptylovací funkce je již implementována a Vám stačí ji jen volat. Zde – pokud se nevyskytne přímá žádost – řešení prozatím neuvádím, jedná se jen o přímou implementaci standardní situace popsané v přednášce i literatuře, nic se tu nemusí „vymýšlet“, předpokládáme tedy, že si zájemci mohou (příp. s knihou či obrazovkou) tamtéž uvedené kódy projít.
PDF vytvořeno zkušební verzí pdfFactory www.fineprint.cz
Statistika Test A, první v tomto souboru, Typická náročná otázka: 1. ... Halda není stabilní datová struktura...“. Respondentů: 50 Otázka Počet chybných odpovědí „lebková“
1 36 X
9 33
5 20
10 20
7 10
2 9 X
4 9 X
8 7
6 4
3 0 X
Test B, druhý v tomto souboru, Typická náročná otázka: 10 . ...Žádná z uvedených datových struktur nemá definován index Respondentů: 45 Otázka Počet chybných odpovědí „lebková“
10 27
4 17 X
9 17
5 16
PDF vytvořeno zkušební verzí pdfFactory www.fineprint.cz
1 13 X
8 13
6 9
7 6
2 5 X
3 2 X