AP15, IN15 Datové struktury a jejich implementace

Zadání

(seznam, zásobník, fronta, binární strom, obecný strom, vyhledávací stromy a jejich modifikace. Implementace binárních a vyhledávacích stromů a operací nad nimi)

Vypracování

Základní informace

Pro ukládání hodnot používáme v programech vedle jednoduchých proměnných různé datové struktury. Na ty se lze dívat ze dvou pohledů:

  • Z pohledu jejich vnitřní realizace (způsobu uložení dat v paměti) rozlišujeme např. pole, záznam, množinu, řetězec…
  • Podle logiky přístupu k jednotlivým položkám dat rozlišujeme např. strom, seznam, zásobník, frontu…

V této otázce se budeme zabývat některými základními datovými strukturami podle logiky přístupu k jednotlivým položkám dat (druhý pohled).

Seznam

Seznam je datová struktura pro ukládání údajů, která je na rozdíl od datové struktury množina tvořena posloupností prvků s pevně stanoveným pořadím. V seznamu se mohou nacházet opakovaně stejné údaje, což je jeho další důležitá odlišnost od množiny. Do seznamu chceme mít schopnost ukládat nové hodnoty, vypouštět z něj údaje, popř. i testovat, zda je daná hodnota v seznamu obsažena. Pro implementaci seznamu se nabízí několik možností:

  • Implementace pomocí dynamického pole: Tento seznam bývá implementován pomocí dynamicky alokovaného pole, které se v případě potřeby (jakmile počet prvků překročí alokované místo) realokuje na dvojnásobek. Je tomu tak proto, že na seznam délky n připadá log2(n) realokací. Kromě toho si musíme pamatovat počet uložených prvků (velikost seznamu) a velikost alokovaného pole (kapacitu seznamu). Na rozdíl od klasického pole můžeme prvky libovolně odebírat a přidávat a nemusíme znát předem jejich počet. Výhodou je rychlý přístup k jednotlivým prvkům (O(1)), nevýhodou pomalé odebírání a vkládání prvků doprostřed seznamu (O(n)). Při tomto úkonu se všechny prvky za inkriminovaným místem musí posunout o jednu pozici doleva či doprava.

  • Implementace pomocí lineárního (jednostranného) spojového seznamu: Základem je záznam, obsahující uloženou hodnotu a ukazatel na následující prvek. Ukazatel posledního prvku je prázdný. Přístup k prvkům je značně pomalejší (O(n) místo O(1)), ale odebírání a vkládání prvků doprostřed seznamu probíhá v konstantním čase.

  • Implementace pomocí oboustranného spojového seznamu: Oproti jednostrannému spojovému seznamu jeho záznam obsahuje i ukazatel na předchozí prvek. (Ukazatele prvního a posledního prvku jsou prázdné.) Umožníme tak procházení směrem od konce na začátek, musíme však v paměti udržovat dvakrát více ukazatelů.

Pomocí seznamu se dá lehce implementovat zásobník nebo fronta. Rozdíl je pouze v tom, do jaké části seznamu se prvky přidávají a z jaké se odebírají.

Zásobník

Zásobník je asi nejpoužívanějším typem seznamů. Je to takový seznam, u něhož jeden konec (tzv. vrchol zásobníku) slouží k přidání i odebírání prvků. Prvky se nemohou přidávat ani odebírat na druhém konci seznamu (označovaném jako dno zásobníku) ani nikde uprostřed. Kdykoli tedy chceme odebrat jeden prvek ze zásobníku, bude to ten, který byl do něj vložen jako poslední (je momentálně na vrcholu zásobníku). Zásobník proto bývá někdy označován jako struktura typu LIFO (last in - first out). Používá se např. jako základní datová struktura při řízení průchodu do hloubky, při zpracování aritmetických výrazů, při realizaci volání procedur a funkcí apod. Z hlediska obsluhy je to nejjednodušší typ seznamu.

Implementace zásobníku pomocí pole

První prvek pole vždy představuje dno zásobníku. Vedle vlastního pole dat použijeme ještě jednu proměnnou, která bude v každém okamžiku udávat index toho prvku pole, kde je momentálně vrchol zásobníku.

    const Maxdelka = N; {N je číslo omezující maximální délku zásobníku}      
    var zasobnik : array[1..Maxdelka] of datovytyp; 
    vrchol : 0..Maxdelka; 
 
    procedure Vytvor; 
    begin 
       vrchol := 0; 
    end; 
 
    procedure Vloz(X: datovytyp); 
    begin 
       if vrchol = Maxdelka then begin {ošetření překročení maximální velikosti} 
          write('Pozor - zasobnik je plny.'); 
          Halt; 
       end; 
 
       else begin 
          vrchol := vrchol + 1; 
          zasobnik[vrchol] := X; 
       end; 
    end; 
 
    procedure Odeber(var X: datovytyp); 
    begin 
       if vrchol = 0 then begin      {ošetření prázdnosti zásobníku} 
          write('Pozor - zasobnik je prazdny.'); 
          Halt; 
       end; 
       else begin 
          X := zasobnik[vrchol]; 
          vrchol := vrchol - 1; 
       end; 
    end; 
 
    function Jeprazdny: boolean; 
    begin 
       if vrchol = 0 then 
          Jeprazdny := true; 
       else 
          Jeprazdny := false; 
    end; 

Implementace zásobníku lineárním spojovým seznamem (pomocí ukazatele)

Vystačíme si s obyčejným jednosměrným seznamem. Je jen třeba si uvědomit, v jakém směru mají být jednotlivé prvky seznamu zřetězeny. Přidávání prvků na oba konce jednosměrného seznamu je snadné, vypouštění prvku ze začátku jednosměrného seznamu také. Protože vypuštění posledního prvku je ale o dost náročnější (bylo by třeba nalézt předposlední prvek, k čemuž je nutné projít celý seznam od začátku), programuje proto zásobník vždy tak, aby v pořadí první prvek spojového seznamu představoval vrchol zásobníku.

    type spoj = ^element; 
    element = record 
       hodnota: datovytyp; 
       dalsi: spoj; 
    end; 
    var zasobnik : spoj; 
 
    procedure Vytvor; 
    begin 
       zasobnik := nil; 
    end; 
 
    procedure Vloz(X: datovytyp); 
       var pom: spoj; 
    begin 
       new(pom); 
       with pom^ do begin 
          hodnota := X; 
          dalsi := zasobnik; 
       end; 
       zasobnik := pom; 
    end; 
 
    procedure Odeber(var X: datovytyp); 
       var pom: spoj; 
    begin 
        if zasobnik = nil then begin 
           write('Zasobnik je prazdny.'); 
           Halt; 
        end; 
        else begin 
           X := zasobnik^.hodnota; 
           pom := zasobnik; 
           zasobnik := zasobnik^.dalsi; 
           dispose(pom); 
        end; 
    end; 
 
    function Jeprazdny: boolean; 
    begin 
       if zasobnik = nil then 
          Jeprazdny := true; 
       else 
          Jeprazdny := false; 
    end; 

Fronta

V seznamu označovaném jako fronta se pracuje s uloženými daty takovým způsobem, jaký odpovídá čekání lidí ve frontě v běžném životě. Přicházející se řadí za sebe; kdo dřív přišel, bude dříve obsloužen a odejde. Do seznamu dat typu fronta jsou proto na jednom konci („příchod“) vkládány nové prvky, zatímco z druhého konce („odchod“) jsou odebírány prvky vyřazované. V anglicky psané literatuře bývá fronta označována jako FIFO (first in - first out).

Fronta se v programech používá tehdy, pokud potřebujeme dočasně odložit nějaká data a zachovat pro další zpracování jejich původní pořadí. Slouží jako základní datová struktura pro řízení průchodu do šířky. Její programová realizace polem i dynamicky je o něco komplikovanější, než tomu bylo v případě zásobníku.

Implementace fronty pomocí pole

Frontu můžeme naprogramovat pomocí pole, pokud známe horní odhad její maximální možné délky. Budeme přitom potřebovat dvě celočíselné proměnné, které budou udávat indexy těch prvků pole, kde je uložen první prvek fronty (tj. začátek fronty, odchod) a poslední (konec fronty, příchod). Opakovanými operacemi vkládání a vypouštění prvků se budou hodnoty obou těchto proměnných stále zvyšovat, jak se bude směrem k vyšším indexům posunovat obsazená část pole. Tak by se mohlo po čase stát, že ačkoli aktuální délka fronty nikdy nepřekročí velikost pole, nebude možné vložit do fronty další údaj, neboť poslední prvek pole bude obsazen. Na toto nebezpečí existují tři základní varianty řešení:

  • Intuitivní: Posouvat v poli všechny prvky fronty o jedno místo směrem k nižším indexům při každém vypuštění prvku. Díky tomu bude začátek fronty neustále udržován v prvním prvku pole. Postup je to správný a na naprogramování jednoduchý, ale dost neefektivní.
  • Lepším řešením je posouvat v poli frontu pouze tehdy, když je to nutné, tj. není-li již kam vložit novou hodnotu. V takové situaci se obsah pole přemístí najednou tak, aby fronta začínala v prvním prvku pole. Proti předchozímu řešení se přesuny prvků provádějí najednou o větší vzdálenost a méně často, výpočet je proto celkově rychlejší.
  • Nejlepší pak samozřejmě je data uložená v poli vůbec nepřesouvat. Představíme-li si, že pole je jakoby zatočené dokola a že po posledním prvku pole následuje opět první prvek, při vlastní programové realizaci nám pak stačí pouze přepočítávat indexy. Trochu složitějším se stane testování neprázdnostni fronty (při odebírání prvku) nebo zda by její délka přidáním dalšího prvku nepřekročila kapacitu pole. Pro tento účel je vhodné zavést ještě jednu celočíselnou proměnnou, která bude udávat počet prvků ve frontě.

Implementace fronty pomocí spojového seznamu

K naprogramování fronty pomocí lineárního spojového seznamu nám opět postačí jednosměrný seznam. Podobně jako v případě zásobníku musíme jen dobře zvolit směr zřetězení prvků v seznamu. K docílení efektivnosti je opět třeba frontu reprezentovat tak, aby její začátek (odchod) byl na začátku seznamu a její konec (příchod) na konci seznamu. Každý uzel zařazený do fronty tedy obsahuje ukazatel na svého následníka. Je to obráceně, než bývá zvykem v běžném životě (např. v čekárně u lékaře nebo u holiče), kde si lidé zpravidla pamatují svého předchůdce, tj. po kom přijdou na řadu.

Další typy front

Existují i různé modifikace fronty, jako tzv. obousměrná fronta (vkládat i odebírat lze na obou jejích koncích) či tzv. prioritní fronta (seznam, který není uspořádán v pořadí příchodu prvků, ale podle jejich priorit - každý zařazovaný prvek má svou prioritu a při vkládání není zařazován na konec fronty, ale „předbíhá“ všechny prvky fronty, které mají nižší prioritu než on). Realizace prioritní fronty pomocí seznamu je však méně efektivní, proto se prioritní fronta obvykle reprezentuje binární haldou.

Strom

Pojem strom je v teorii grafů formálně definován jako zvláštní případ acyklického grafu. Zvláštní skupinu mezi stromy pak tvoří tzv. zakořeněné stromy, v nichž je jeden význačný vrchol označen jako kořen stromu.

V informatice se jako strom obvykle označuje útvar, který je složen z jednotlivých vrcholů a má následující tvar:

  • Jeden význačný vrchol je kořenem stromu.
  • Kořen má několik následníků (či „synů“), každý z nich má zase své následníky atd. Přitom každý vrchol s výjimkou kořene má právě jednoho svého předchůdce („otce“).
  • Některé vrcholy nemají již žádné následníky, ty se nazývají listy.

Výška stromu, tj. počet jeho hladin, je pro prázdný strom rovna 0 a pro neprázdný strom je rovna počtu uzlů na jeho nejdelší větvi. V programech pracujeme pouze se stromy s konečnou výškou.

Binární strom

Zvláštním případem stromu je strom binární, v němž může mít každý vrchol nejvýše dva následníky. S binárním stromem se v programování setkáváme častěji než se stromem obecným. Slouží například pro reprezentaci aritmetického výrazu s binárními operátory nebo pro uložení dat do binárního vyhledávacího stromu či do haldy.

Vyhledávací stromy a jejich modifikace

Datovou strukturu strom lze výhodně použít k ukládání údajů a vyhledávání nad nimi. Bi
nární vyhledávací strom
je (na rozdíl od předchozích trochu složitější) datová struktura používaná pro ukládání a vyhledávání údajů. Je to binární strom, v jehož uzlech jsou umístěna data. Přitom pro uspořádání hodnot uložených ve stromu platí následující pravidlo:

  • Je-li ve vrcholu V uložena hodnota X, pak všechny uzly v levém podstromu vrcholu V obsahují hodnoty menší, nebo rovny X a všechny uzly v pravém podstromu vrcholu V obsahují hodnoty větší, nebo rovny X. (Hodnoty rovny X je výhodné povolit v pravém i levém podstromu z důvodu krajních případů, například když je BVS vyvážený (viz. níže) a obsahuje jen prvky jedné hodnoty)

Časová složitost operací nad vyhledávacím stromem závisí na jeho výšce. Bude-li množina uložených údajů předem pevně dána, není problém vybudovat tzv. vyvážený vyhledávací strom. Pokud se budou data v průběhu programu měnit, lze pro zajištění vyváženosti či další optimalizace vyhledávání obecně a v různých konkrétních případech zavést některou z modifikací vyhledávacích stromů:

  • Dokonale vyvážené stromy mají nejlepší možné vyvážení, přičemž přesný význam tohoto označení v literatuře není ustálen. Udržování binárního stromu v dokonale vyváženém stavu je ale každopádně poměrně obtížné a vzhledem k srovnatelné časové složitosti s následujícím typem, na který jsou přitom kladeny slabší podmínky, i zbytečné.
  • Binární strom se nazývá AVL-stromem, jestliže pro každý uzel stromu platí, že výšky jeho levého a pravého podstromu se liší nejvýše o 1. Každý dokonale vyvážený strom je současně AVL-stromem, opačné tvrzení však neplatí. V AVL-stromu je do každého uzlu přidána navíc „technická položka“, která může nabývat hodnot -1, 0 nebo 1 a udává, jak se liší výška jeho levého a pravého podstromu.
  • Datovou strukturou zajišťující vyváženost stromu již přímo z podstaty způsobu ukládání dat jsou 2-3-stromy. Rozlišujeme v nich dva typy uzlů. Zvláštní význam mají uzly bez následníků, ve kterých jsou uložena pouze data, naopak všechny ostatní uzly (tzv. vnitřní uzly) slouží pouze k vytvoření vyhledávací struktury. Každý vnitřní uzel obsahuje dva klíče pro vyhledávání a tři ukazatele na následníky. Struktura 2-3-stromu je definována následujícími dvěma pravidly:
    1. Každý vnitřní uzel stromu má 2 nebo 3 následníky (odtud je také odvozen název struktury).
    2. Všechny listy stromu jsou ve stejné výšce (na stejné hladině).

Význam klíčů ve vnitřních uzlech je obdobný jako u binárních stromů: První klíč udává maximální hodnotu uloženou v levém podstromu, na nějž ukazuje první ukazatel, druhý klíč může udávat maximální hodnotu uloženou v prostředním podstromu (pokud má uzel jen dva následníky, tento klíč není definován). Pro uložení N údajů je třeba 2-3-strom o N listech. Pro mnohá N lze sestavit více ekvivalentních 2-3-stromů. Výška 2-3-stromu je logaritmicky úměrná počtu údajů N.

  • Červeno-černé stromy (red-black trees) jsou vyvážené binární vyhledávací stromy, podobné AVL stromům. Narozdíl od AVL stromů nesou v uzlu místo „technické položky“ informaci o barvě (černá/červená), což spolu s následujícími pravidly zaručuje, že je strom vyvážený:
    1. Uzel má buďto černou nebo červenou barvu.
    2. Kořen má černou barvu.
    3. Každý následník červeného uzlu má černou barvu.
    4. Každá větev obsahuje stejný počet černých uzlů.

Tato pravidla nám zaručují, že nejdelší cesta z kořene do nějakého listu není delší než dvojnásobek nejkratší cesty z kořene do nějakého (jiného) listu.

Halda

Halda (heap) je speciální datová struktura, která má také tvar binárního stromu, ale využívá se nejen k vyhledávání, ale např.
i třídění pomocí haldy. Halda je binární strom, pro který jsou splněny následující podmínky:1)

  1. V každé hladině od první až do předposlední je maximální možný počet uzlů, tzn. v k-té hladině je 2k-1 uzlů.
  2. V poslední hladině jsou všechny uzly umístěny co možná nejvíce „vlevo“, tj. při procházení stromu do hloubky zleva nejprve mají uzly předposlední hladiny dva následníky, pak může být jeden s jedním následníkem a zbývající takové uzly jsou pak už bez následníků.
  3. Pro každý uzel platí, že hodnota v něm uložená je menší než hodnota v jeho libovolném následníkovi.

Implementace binárních a vyhledávacích stromů a operací nad nimi

Binární strom lze v programu reprezentovat např. v následující dynamické podobě:

    type Uk = ^Uzel; 
         Uzel = record 
           Info: T;  {uložená informace} 
           L,P : Uk  {levý a pravý následník} 
         end; 

Teoreticky je možné jakýkoliv obecný strom reprezentovat stromem binárním (a tedy v této struktuře), k čemuž se využívá tzv. kanonická reprezentace stromu - použitý trik spočívá v tom, že v každém uzlu je uložen odkaz na prvního syna a na „bratra“ tohoto uzlu. Z libovolného uzlu se tak dostaneme ke všem jeho následníkům tak, že přejdeme na prvního z nich po ukazateli na syna a a mezi následníky pak přecházíme pomocí jejich ukazatelů na bratry.

Vyhledávání vrcholu s hodnotou X v daném binárním vyhledávacím stromě je snadné. Začneme v kořeni stromu a postupujeme směrem k listům na základě porovnání hodnoty uložené v uzlu stromu s hodnotu X. Prohledávání končí buď nalezením uzlu s hodnotu X, nebo zjištěním, že v potřebném směru následník neexistuje a hodnota X tedy není ve stromě uložena. Počet provedených porovnání je menší nebo roven výšce stromu, u vyvážených vyhledávacích stromů je tedy časová složitost vyhledávání logaritmická.

Při přidávání uzlu do binárního vyhledávacího stromu se postupuje stejně jako při vyhledávání, jen je třeba si zapomatovat uzel, v němž procházení stromem skončilo a pod který je třeba zapojit nový uzel s přidávanou hodnotou. Složitost je opět logaritmická, ale ta může být narušena, jestliže stromy průběžně nevyvažujeme.

Operace vypouštění uzlu je o něco komplikovanější - je třeba do zbytku stromu správně navázat případné následníky rušeného uzlu - ale také ji lze implementovat s logaritmickou složitostí.

Implementace AVL-stromu spočívá v zavedení pomocné „technické položky“ (zmíněné výše) a provedení vyvážovacího algoritmu po každém provedení operace nad stromem, která způsobila nevyváženost stromu. Vlastní algoritmy jsou však dosti dlouhé a komplikované a dobře jsou popsány v literatuře a je dostupná jejich implementace v mnoha programovacích jazycích.2)

Operace vyhledávání v 2-3-stromě probíhá podobně jako v binárnéím vyhledávacím stromě, při průchodu se orientujeme podle hodnot klíčů. Trochu náročnější je vkládání nových hodnot a jejich vypouštění - příslušné algoritmy představují vždy jeden průchod od kořene k listu (vyhledání místa, kam se má připojovat nebo kde se má rušit) a poté jeden průchod zpět ke kořeni (modifikace struktury stromu a hodnot klíčů). Z důvodu závislosti počtu operací na hloubce stromu je časová složitost všech těchto operací opět logaritmická.

Vyhledávání, vkládání i rušení uzlu v červeno-černém stromě probíhá stejně jako v binárním vyhledávacím stromě. Vložení nebo odebrání prvku však může způsobit porušení pravidel. Proto je nutné v takovém případě strom vyvažovat. Vyvažování se provádí přebarvováním uzlů a rotací větví stromu a je dobře popsáno v literatuře3), svou komplikovaností ovšem přesahuje rozsah toto textu. Co je podstatné, je fakt, že i přes toto komplikované vyvažování mají operace operace vložení a odebrání prvku logaritmickou složitost – O(\mathrm{log}_2\,n). Složitost vyhledání prvku je ve stejné třídě.

Implementace haldy

Svou strukturou zajišťuje halda nalezení minimálního prvku v konstantním čase, provedení operací odebrání minima a přidání nového prvku pak v čase logaritmickém. Její výhodou je algoritmická jednoduchost a možnost snadné realizace v poli, známe-li horní odhad maximálního počtu prvků v haldě. Přidání nového prvku do haldy probíhá jeho připojením na první volné místo v haldě (tj. konec obsazené části pole; aby byla zachována pravidla 1 a 2 pro haldu) a provádění série výměn hodnoty v uzlu s hodnotou v jeho předchůdci, dokud je to třeba (aby bylo zachováno pravidlo 3). Vypuštění minimálního prvku probíhá dosti podobně - hodnotu z kořenu smažeme a namísto toho do kořene přesuneme hodnotu z posledního uzlu haldy, kterou pak necháme dle potřeby „probublat“ na její správné místo dolů.

Kam dál

Předměty

  • FI:IB002 Návrh algoritmů I (jaro 2008), RNDr. Libor Škarvada

Použitá literatura

  • TÖPFER, Pavel: Algoritmy a programovací techniky. PROMETHEUS : Praha. 1995. 1. vydání. ISBN 80-85849-83-6.

Vypracoval

Marek Blahuš ICQ: 105136489 - většina textu otázky
Martin Gracík - implementace zásobníků v Pascalu
Shkodran Gerguri - červeno-černé stromy

Z mé strany je toto všechno, připomínky pište buďto do diskuze, nebo klidně i přímo upravujte, budu stránku průběžně sledovat. (Marek Blahuš)

Otázku si přečetl pan RNDr. Libor Škarvada a rámcově prošel. Jeho podněty pro doplnění textu, opravy nesrovnalostí a odstranění matoucích či k otázce se nevztahujících textů byly do otázky zaneseny. Tato kontrola je jen rámcová, stále se může stát, že v otázce zůstala zapomenutá chybka či nesrovnalost, vyučující za toto nenese odpovědnost, berte tuto rámcovou kontrolu jako formu pomoci od vyučujících pro studenty.

1)
Tyto podmínky platí pro častější, tzv. minimovou haldu. Maximová halda je definována podobně, až na nerovnost v bodě 3, která je obrácená.
2)
Popis rotací v AVL-stromech naleznete např. zde: http://ksvi.mff.cuni.cz/~holan/
3)
včetně materiálů Libora Škarvady ke kurzu Návrh algoritmů I

Diskuze

, 2008/06/13 20:13

Ja myslim ze by bylo lepsi napsat je ve funcku, na pochopeni je to lepsi, co rikas?

, 2008/06/15 15:03

Já myslím, že nejlepší by bylo to sem opsat ze skript k návrhu algoritmů 1., kde je to všechno krásně rozepsaný…

, 2008/06/16 11:32

Nejpozději dnes v noci se tu objeví vypracovaný text otázky, který jsem slíbil. Omlouvám se za zpoždění.

, 2008/06/16 18:35

Skvela zprava, diky za info

, 2008/06/17 02:24

První půlka, zbytek doplním ráno.

, 2008/06/17 21:36

A které ráno myslels? :)

, 2008/06/17 23:36

Ked tak to skuste opisat odtialto: http://www.fi.muni.cz/~xhalic1/statnice/ (je to tam cca tak ako to bolo v navale)

, 2008/06/18 20:15

Jak to vypada?

, 2008/06/19 07:17

K datovým strukturam mám vypracovanou otázku zde: http://smejkal.quonia.cz/skola/statnice/I15.pdf
Zdroje: Scripta z návalu a net.
Jak se provádí rotace AVL a BVS stromu je k nalezení zde: http://ksvi.mff.cuni.cz/~holan/

, 2008/06/19 12:35

Včera jsem si to podle knihy nachystal, právě to jdu přepsat sem. Netuším, jaké všechny modifikace stromů po nás mohou chtít - např. vyvažování AVL-stromů je podle mne dost nudný proces s rozsáhlými kódy, takže bych tu v souladu s tou knihou nechal spíše jen zmínku o tom, že to existuje a jak se to tak asi dělá. Taky nevím, do jaké míry tu popisovat třeba haldu, když už je zmíněna i v otázce třídění haldou. Ale asi kratší zmínka se zase bude hodit.

, 2008/06/19 13:13

Super to se bude hodit, právě jsem to chtěl vypracovat, ale ty to zvládneš kvalitněji :)

, 2008/06/19 14:10

Tak už to tu konečně je a pokud do toho chcete někdo zasahovat, tak teď je na to vhodný čas. Doufám, že jsem z definice otázky zachytil vše podstatné a naopak neuvedl příliš nesouvisejících věcí (jen těžko se např. rozhoduje, které všechny modifikace stromů zmínit, nebo rozlišuje, co je popis takové modifikace, co je její implementace a co už je něco příliš detailního, co se sem už nemá vlézt). Pokud si bude chtít někdo v otázce zmínit nějakou další modifikaci (nebo naopak některou zde uvedenou nezmínit), jistě má na to právo a nemyslím si, že máme povinnost znát úplně všechny, takže si každý může trochu vybírat. Pokud by někomu ale přišlo, že tady chybí informace o nějaké zvláště podstatné modifikaci, může navrhnout jejich doplnění.

Algoritmy na rotaci AVL-stromů zde neuvádím, jen na ně odkazuji (díky Michalovi Smejkalovi za odkaz), podobně jako nejsou ani v knize, ze které čerpám. Pochybuji, že by se na ústní zkoušce zvládlo něco víc než nastínění způsobu funkce implementace operací nad stromy, které jsou v takovém rozsahu popsány i zde v textu otázky.

Technická: Pokud by někdo přišel, jak zařadit odstavec začínající textem „Význam klíčů“ (nachází se totiž po vnořeném číslovaném seznamu) jako pokračování původní položky odrážkového seznamu (tedy ne jako novou), nechť to prosím opraví - s DocuWiki se mi toho nepodařilo dosáhnout.

Pokud se zde v brzké době shodneme na plus minus definitivní podobě otázky, mohu požádat Libora Škarvadu o její zkontrolování.

, 2008/06/21 22:47

Dostali jsme předběžně slíbeno, že kontrola bude provedena během neděle.

, 2008/06/19 21:04

Možno by nebolo zlé aspoň spomenúť typt háld - binárna, binomiálna a Fibonacciho. V otázke to nie je, takže ak si myslíte, že netreba, tak ok.

, 2008/06/21 11:30

V návalu I se dělaly také červeno-černé stromy, možná by bylo vhodné je to zmínit.

, 2008/06/21 13:41

Přidal jsem červeno-černé stromy. Vzhledem k jejich komplikovanosti se mi zdá rozsah, v jakém jsem je popsal, naprosto dostačující.

, 2008/06/24 16:52

Pre Cerveno-Cierne stromy plati, ze kazdy cerveny uzol ma dvoch ciernych nasledovnikov.

, 2008/06/25 17:17

Změnil jsem sadu pravidel pro červeno-černé stromy na jinou, kterou jsem našel v jiném zdroji a která vypadá jako snazší a přitom ekvivalentní. Obsahuje mj. i pravidlo zde formulované Petrem Škodou.

, 2010/01/31 11:26

Kompletně jsem přepsal implementaci seznamů, to předchozí vypracování nemělo hlavu, ani patu. Doplnil jsem tam i obrázky (dynamický seznam je moje dílo, spojové seznamy jsou public domain z Wikipedie).

You could leave a comment if you were logged in.
home/inf/ap15.txt · Poslední úprava: 2020/04/12 16:56 (upraveno mimo DokuWiki)
Nahoru
CC Attribution-Noncommercial-Share Alike 4.0 International
chimeric.de = chi`s home Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0