10. Dynamické datové struktury

Slides:



Advertisements
Podobné prezentace
Orbis pictus 21. století Tato prezentace byla vytvořena v rámci projektu.
Advertisements

Programování funkcí v Excelu (pole)
Programovací jazyk C++
Třída SIMSET je druhou standardní systémovou třídou, která obsahuje prostředky pro práci se spojovými seznamy. KRUHOVÉ SPOJOVÉ SEZNAMY Spojový seznam –
Pascal - příklady.
Přednáška 11 Jiří Šebesta
Vnitřní řazení v poli (in sito)
1 Vnitřní řazení s využitím dynamických struktur Tvorba spojového seznamu je vcelku triviální záležitostí: a)Vytvořím prázdný seznam příkazem LIST:=nil.
Cvičení Úloha 1: Rozhodněte zda posloupnost znaků v poli délky n tvoří palindrom (slovo, které je stejné při čtení zprava i zleva). Př.: [a,l,e,l,a] [a,n,n,a]
Spojové struktury Spojová struktura ( linked structure ):
Fronta - a)Implementace s využitím statických struktur (pole) b)Implementace s využitím dynamických struktur (spojového seznamu) odebírá se ze začátku.
Semestrální práce KIV/PT Martin Kales Hana Hůlová.
Programování v Pascalu Přednáška 9 RNDr. Hana Havelková.
Třídění Seminář IVT. Definice uspořádání skupiny dat (záznamů) dle daného klíče vzestupně (od nejmenší do největší hodnoty klíče) sestupně (od největší.
Alg51 Rozklad problému na podproblémy Postupný návrh programu rozkladem problému na podproblémy –zadaný problém rozložíme na podproblémy –pro řešení podproblémů.
Principy překladačů Běhová podpora Jakub Yaghob. Běhová podpora Statická podpora jazyka Překladač Interface na knihovny Hlavičkové soubory Dynamická podpora.
Programování v Pascalu Přednáška 7
Materiály k přednášce Úvod do programování Ondřej Čepek.
ADT Strom.
Skip-List je datová struktura, která může být použita jako náhrada za vyvážené stromy. představují pravděpodobnostní alternativu k vyváženým stromům (struktura.
1 Vyhledávání Principy vyhledávání Klasifikace klíče:  Interní klíč – je součástí prohlížených záznamů  Externí klíč – není jeho součástí, je jím např.
Informatika I 3. přednáška
Procedury a funkce Základní charakteristika a použití v programu.
Orbis pictus 21. století Tato prezentace byla vytvořena v rámci projektu.
Vyučovací hodina 1 vyučovací hodina: Opakování z minulé hodiny 5 min Nová látka 20 min Procvičení nové látky 15 min Shrnutí 5 min 2 vyučovací hodiny: Opakování.
13AMP 6. přednáška Ing. Martin Molhanec, CSc.. Co jsme se naučili naposled Synchronizace procesů Synchronizace procesů Producent-Konzument Producent-Konzument.
Algoritmy a programovací techniky
Organizace a zpracování dat I
Radim Farana Podklady pro výuku
Algoritmizace a programování Třídící algoritmy - 12
ALGORITMIZACE A ZÁKLADY PROGRAMOVÁNÍ ŘAZENÍ PRVKŮ – PŘÍMOU VÝMĚNOU (BUBBLESORT) Vytvořila: RNDr. Ivanka Dvořáčková Gymnázium K. V. Raise, Hlinsko, Adámkova.
Další abstraktní datové typy
JavaScript Podmínky, cykly a pole.
Proměnná typu "pole" Mezi proměnné typu "pole" patří všechny superglobální proměnné. Mezi proměnné typu "pole" patří všechny superglobální proměnné. To.
Informatika I 7. přednáška RNDr. Jiří Dvořák, CSc.
Informatika I 8. přednáška RNDr. Jiří Dvořák, CSc.
Datové typy a struktury
Algoritmizace a programování Binární soubory - 14 Mgr. Josef Nožička IKT Algoritmizace a programování
Orbis pictus 21. století Tato prezentace byla vytvořena v rámci projektu.
STROMY Datová struktura sestávající z uzlů
10. Dynamické proměnné Dynamická proměnná se nezavádí deklarací proměnných, ale vzniká za běhu programu provedením speciálního příkazu. Nemá přidělen žádný.
7. Typ soubor Souborem dat běžně rozumíme uspořádanou množinu dat, uloženou mimo operační paměť počítače (na disku). Pascalský soubor je abstrakcí skutečného.
Počítače a programování 1 7.přednáška. Základy Pole ve třídách a metodách Pole Arrays.
Vazby dynamických proměnných,databázové systémy Přednáška č. 10.
doc. RNDr. Zdeněk Botek, CSc.
Jazyk C A0B36PRI - PROGRAMOVÁNÍ Část II.
Datové typy IB111: Datové typy. Data a algoritmizace jaká data potřebuji pro vyřešení problému? jak budu data reprezentovat? jaké operaci s nimi potřebuji.
PROGRAMOVÁNÍ 3ITA,3ITB Jaroslav Burdys Hlavní zdroj:
Programovací jazyk C# 4. část - cykly.
Úvod do programování 11. hodina
Programování ENUM, SWITCH,pole jednorozměrná a vícerozměrná, deklarace, inicializace, kopírování, porovnání Erik Král.
Výška stromu - algoritmus
Programovací jazyk C++
C# konzole – Podíl dvou čísel, podmínka IF
STROMY A KOSTRY Stromy a kostry - odst. 3.2.
Znázornění dopravní sítě grafem a kostra grafu Předmět: Teorie dopravy - cvičení Ing. František Lachnit, Ph.D.
Abstraktní datové typy
Programování 2. hodina RNDr. Jan Lánský, Ph.D.
Strukturované typy proměnných v programovacím jazyce Pascal - 2.hodina
ADT zásobník - příklad Prakticky aplikovatelný příklad využití ADT zásobník je vyhodnocování aritmetických výrazů v Postfixové notaci: Pro zápis aritmetických.
Abstraktní datové typy
© Copyright Radim Štefan
Dynamické proměnné (1) Proměnné, jejichž počet a (nebo) velikost pa-měti využívané těmito proměnnými se v prů-běhu programu mění Dynamické proměnné lze.
Oblast platnosti identifikátoru (1)
Opakování základních příkazů a syntaxí v programovacím jazyce Pascal
Fronta (1) Dynamická datová struktura typu FIFO (First In First Out)
Algoritmizace a datové struktury (14ASD)
ZAL – 7. cvičení 2016.
AVL a B-stromy cvičení Radek Mařík.
Algoritmizace a datové struktury (14ASD)
Transkript prezentace:

10. Dynamické datové struktury Statická datová struktura - její rozsah se během provádění programu nemění - pole, záznamy. Dynamická datová struktura - její rozsah se během výpočtu mění. Vytváří se pomocí dynamických proměnných, jejich spojováním do seznamů. Dynamická proměnná je typu záznam a obsahuje jeden jeden nebo více ukazatelu na tento typ záznam. Nejjednodušší dynamickou datovou strukturou je lineární seznam, ve kterém každá dynamická proměnná ukazuje na svého následníka a jedna proměnná typu ukazatel ukazuje na jeho začátek.

Operace nad spojovým seznamem: - přidání prvku na začátek seznamu: prvek^.dalsi:=zacatek; zacatek:=prvek; - odebrání prvního prvku v seznamu: zacatek:=zacatek^.dalsi; - provedení operace pro všechny prvky v seznamu: p:=zacatek; s:=0; while p <> nil do begin s:=s + p^.hodnota; {proveden operace s p^} p:=p^.dalsi; end;

- přidání prvku na konec seznamu: posledni^.dalsi:=prvek; posledni:=prvek; - vložení prvku za označený prvek prvek^.dalsi:=za^.dalsi; za^.dalsi:=prvek;

- vložení prvku před označený prvek Procedura vyhledá prvek předcházející prvek před který chceme vložit a provede vložení za tento prvek. procedure vlozpred(var zacatek:spoj; prvek,pred:spoj); var p:spoj; begin if pred=zacatek then begin prvek^.dalsi:=zacatek; zacatek:=prvek end else begin p:=zacatek; while p^.dalsi<>pred do p:=p^.dalsi; prvek^.dalsi:=pred; p^.dalsi:=prvek; end;

Je-li seznam rozsáhlý, vkládáme nový prvek tak, že vyměníme hodnoty nového a označeného prvku a nový prvek pak vložíme za označený: procedure vlozpred(pred,prvek:spoj); var pom:integer; begin pom:=pred.hodnota; pred^.hodnota:=prvek^.hodnota; prvek^.hodnota:=pom; prvek^.dalsi:=pred^.dalsi; pred^.dalsi:=prvek; end;

- odebrání označeného prvku: 1. Najdeme prvek, který v seznamu předchází označený prvek procedure odeber(var zacatek:spoj; co:spoj); var p:spoj; begin if co=zacatek then zacatek:=zacatek^.dalsi else begin p:=zacatek; while p^.dalsi<>co do p:=p^.dalsi; p^.dalsi:=co^.dalsi; end;

2. Do označeného prvku přesuneme hodnotu následujícího prvku a tento následující prvek odebereme (nelze pro poslední prvek). procedure odeber(co:spoj); begin if co^.dalsi<>nil then begin co^.hodnota:=co^.dalsi^.hodnota; co^.dalsi:=co^.dalsi^.dalsi; end;

Lineární seznam může být spojen ukazateli obousměrně - kromě ukazatele na další prvek obsahuje proměnná typu objekt také ukazatel na předchozí prvek. type spoj=^objekt objekt=record / /zacatek konec hodnota:integer; dalsi,predchozi:spoj; end; Taková datová struktura je vhodná například pro tvorbu textového editoru. Speciálním případem jednosměrně vázaného lineárního seznamu je zásobník nebo fronta.

Zásobník Zásobníkem rozumíme takovou dynamickou datovou strukturu, z níž se prvky vybírají v opačném pořadí než v jakém se do ní vkládají. Vybíráme tedy vždy poslední vložený prvek (podle toho se zásobníky také nazývají struktury LIFO - z anglického Last-In-First-Out). Příkladem použití zásobníku je historie v internetových prohlížečích. Když kliknete na zpět, otevře se posledně otevřená stránka. Pro zásobník můžeme definovat tyto základní operace: vytvoření prázdného zásobníku vložení prvku na vrchol zásobníku odebrání prvku z vrcholu zásobníku testování prázdnosti zásobníku Zásobník můžeme v Pascalu implementovat (vytvořit) buď pomocí pole, tedy jako statickou datovou strukturu, nebo pomocí ukazatele, tedy jako dynamickou datovou strukturu.

Implementace pomocí pole: Při této implementaci jsme nuceni omezit maximální velikost zásobníku a překročení této velikosti musíme v programu ošetřit. Také musíme ošetřit opačný stav, kdy chceme ze zásobníku prvek odebrat, ale zásobník je již prázdný. const Maxdelka = N; {N je číslo omezující maximální délka zásobníku} var zasobnik : array[1..Maxdelka] of datovytyp; vrchol : 1..Maxdelka; procedure Vytvor; begin vrchol := 0; end; function Jeprazdny: boolean; if vrchol = 0 then Jeprazdny := true; else Jeprazdny := false;

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; procedure Odeber(var X: datovytyp); if vrchol = 0 then begin {ošetření prázdnosti zásobníku} write('Pozor - zasobnik je prazdny.'); X := zasobnik[vrchol]; vrchol := vrchol - 1;

Implementace pomocí ukazatele: Pokud budeme chtít implementovat zásobník pomocí ukazatele, nemusíme řešit maximální velikost zásobníku. Ta je dána velikostí té části operační paměti, ve které se vytvářejí dynamické proměnné - hromada (heap). Prvky se vkládají a odebírají na začátku jednosměrně vázaného lineárního spojového seznamu. type spoj = ^objekt objekt = record hodnota: datovytyp; dalsi: spoj; end; var zasobnik : spoj; procedure Vytvor; begin zasobnik := nil; function Jeprazdny: boolean; if zasobnik = nil then Jeprazdny := true; else Jeprazdny := false;

procedure Vloz(X: datovytyp); var pom: spoj; begin new(pom); with pom^ do begin hodnota := X; dalsi := zasobnik; end; zasobnik := pom; procedure Odeber(var X: datovytyp); if zasobnik = nil then begin write('Pozor - zasobnik je prazdny.'); Halt; else begin X := zasobnik^.hodnota; pom := zasobnik; zasobnik := zasobnik^.dalsi; dispose(pom);

Fronta Fronta je dynamická datová struktura podobná zásobníku, rozdíl je pouze v tom, že prvky se z fronty odebírají v tom pořadí, v jakém se do fronty vkládají. Jako příklad si můžeme představit frontu nakupujících v obchodě. Podle toho se datový typ fronta také nazývá struktura FIFO - z anglického First-In-First-Out. Pro frontu můžeme definovat tyto operace: vytvoření prázdné fronty vložení prvku na konec fronty odebrání prvku ze začátku fronty test prázdnosti fronty Frontu stejně jako zásobník můžeme implementovat buď pomocí pole, nebo pomocí ukazatele.

Implementace pomocí pole: Při této implementaci musíme neustále vědět, kde fronta začíná, kde končí a kolik má prvků. Také co se týče velikosti, musíme omezit maximální velikost fronty a překročení této velikosti musíme ošetřit. Pokud budeme vkládat prvky do prázdné fronty, bude situace vypadat následovně: Vidíme, že do fronty byly postupně vloženy hodnoty a až f.

. Pokud budeme s frontou pracovat tak, že staré prvky z ní budeme podle potřeby vybírat, nové do ní budeme vkládat, zjistíme, že pro nové vložení nám nemusí zbýt políčko ve frontě, zatímco po odebraných prvcích ze začátku fronty nám zbývají volná a nevyužitá políčka. Situace může vypadat např. takto: Takovýto problém můžeme vyřešit např. tím, že po každém výběru prvku ze začátku fronty můžeme celou frontu přesypat na začátek, neboli všechny prvky budeme přesunovat o jedno místo dopředu.

Jednodušším řešením, které můžeme přirovnat k předchozímu řešení, je použití tzv. kruhové fronty. Za následníka posledního prvku považujeme u takovéto kruhové fronty první prvek. Jak je vidět z obrázku, prvním prvkem je zde prvek s indexem 0 a poslední prvek má index N-1 vzhledem k tomu, že přidávání a odebírání prvků do a z fronty, resp. výpočet indexu prvku, je realizováno pomocí operace modulo N.

V následujícím výpisu jsou procedury vytvoření prázdné fronty, přidání prvku do fronty, odebrání prvku z fronty a funkce testování prázdnosti fronty. const MaxDelka = N; {N je číslo omezující délku fronty} MaxIndex = N-1; var fronta: array[1..MaxDelka] of datovytyp; zacatek, konec: MaxIndex; delka: MaxDelka; procedure Vytvor; begin zacatek := 0; konec := 0; delka := 0; end; function JePrazdna: boolean; if delka = 0 then JePrazdna := true else JePrazdna := false;

procedure Vloz(X: datovytyp); begin if delka = MaxDelka then begin {ošetření překročení maximální velikosti} write('Pozor - fronta je plna.'); Halt; end; else begin fronta[konec] := X; konec := (konec + 1) mod MaxDelka; delka := delka + 1; procedure Odeber(var X: datovytyp); if delka = 0 then begin {ošetření prázdnosti fronty} write('Pozor - fronta je prazdna.'); X := fronta[zacatek]; zacatek := (zacatek + 1) mod MaxDelka; delka := delka - 1;

Implementace pomocí ukazatele: Podobně jako u zásobníku, kontrola maximální velikosti fronty odpadá a maximální velikost fronty je dána velikostí hromady, ve které je fronta dynamicky vytvořena. V proceduře Odeber je použita pomocná proměnná pom typu spoj, kterou využijeme k odstranění prvního prvku fronty. type spoj = ^objekt; objekt = record hodnota: datovytyp; dalsi: spoj; end; var zacatek, konec: spoj; procedure Vytvor; begin new(zacatek); konec := zacatek;

procedure Vloz(X: datovytyp); begin konec^.hodnota := X; new(konec^.dalsi); konec := konec^.dalsi; end; procedure Odeber(var X: datovytyp); var pom: spoj; if zacatek = konec then begin write('Pozor - fronta je prazdna.'); Halt; end else begin X := zacatek^.hodnota; pom := zacatek; zacatek := zacatek^.dalsi; dispose(pom); function JePrazdna: boolean; if zacatek = konec then JePrazdna := true else JePrazdna := false;

Binární strom Složitější dynamickou datovou strukturou je binární strom, ve kterém z každého uzlu vycházejí nejvýše dvě hrany. Vytváří se pomocí typu uzel: type spoj=^uzel; uzel=record hodnota:integer; levy, pravy:spoj; end;

Průchod stromem za účelem provedení nějaké operace pro všechny uzly stromu se řeší pomocí rekurze. Existuje šest způsobů průchodu stromem, které se liší v pořadí provedení těchto kroků: a) proveď operaci v uzlu U b) projdi levý podstrom c) projdi pravý podstrom. Praktický význam mají tři způsoby průchodu, které mají vlastní jména: preorder - a),b),c) inorder - b),a),c) postorder - c),a),b)

Průchod stromem za účelem provedení nějaké operace pro všechny uzly stromu se řeší pomocí rekurze. Existuje šest způsobů průchodu stromem, které se liší v pořadí provedení těchto kroků: a) proveď operaci v uzlu U b) projdi levý podstrom c) projdi pravý podstrom. Praktický význam mají tři způsoby průchodu, které mají vlastní jména: preorder - a),b),c) inorder - b),a),c) postorder - c),a),b) Použitím těchto průchodů pro uvedený příklad stromu obdržíme toto poředí uzlů: preorder: E B A D C F H G I inorder: A B C D E F G H I postorder: A C D B G I H F E

Př.: Ukázka rekurzivní procedury pro výpis hodnot všech uzlů v pořadí určeném metodou preorder. procedure vypis(strom:spoj); begin if strom<>nil then begin write(strom^.hodnota); vypis(strom^.levy); vypis(strom^.pravy); end; Binární vyhledávací strom - pro každý uzel s hodnotou x platí, že všechny hodnoty v levém podstromu jsou menší a v pravém větší než x. Uzly po seřazení metodou inorder tvoří vzestupně uspořádanou posloupnost.

Př.: Rekurzivní procedura pro zařazení do binárního vyhledávacího stromu. procedure zarad(var strom:spoj; x:typhodnoty); begin if strom=nil then begin new(strom); with strom^ do begin hodnota:=x; levy:=nil; pravy:=nil; end else with strom^ do if x<hodnota then zarad(levy,x); else zarad(pravy,x); end;

Př.: Nerekurzivní funkce pro vyhledání uzlu se zadanou hodnotou v binárním vyhledávacím stromu. Funkce vrací ukazatel na daný uzel nebo nil. function hledej(strom:spojů x:typhodnoty):spoj; var konec:boolean; begin konec:=false; repeat if strom=nil then konec:=true else with strom^ do if x<hodnota then strom:=levy if x>hodnota then strom:=pravy else konec:=true until konec; hledej:=strom; end;

Př.: Program pro setřídění souboru čísel pomocí zatřiďování do lineárního dynamického seznamu. program dynamicke_trideni; type spoj = ^objekt; objekt = record hodn : integer; dalsi : spoj; end; var zacatek : spoj;

procedure vytvor_seznam(var zacatek : spoj); var prvek : spoj; procedure zarad_prvek(prvek : spoj; var zacatek : spoj); var za,pom : spoj; begin if prvek^.hodn < zacatek^.hodn then begin prvek^.dalsi := zacatek; zacatek := prvek; end else begin pom := zacatek; repeat za := pom; pom := pom^.dalsi; until (pom = nil)or(prvek^.hodn < pom^.hodn); za^.dalsi := prvek; prvek^.dalsi := pom; end;

begin {vytvor_seznam} if not eof then begin new(zacatek); with zacatek^ do begin readln(hodn); dalsi := nil; end; while not eof do begin new(prvek); readln(prvek^.hodn); zarad_prvek(prvek,zacatek); end; {vytvor_seznam}

procedure tiskni_seznam(zacatek : spoj); var prvek : spoj; pocet : integer; begin if zacatek <> nil then begin write(zacatek^.hodn:5); pocet := 1; prvek := zacatek; while prvek^.dalsi <> nil do begin prvek := prvek^.dalsi; write(prvek^.hodn:5); pocet := pocet + 1; if pocet mod 5 = 0 then writeln end; writeln; vytvor_seznam(zacatek); tiskni_seznam(zacatek); end.