1. D Y N A M I C K É DAT O V É STRUKTUR Y

Podobné dokumenty
Implementace seznamů do prostředí DELPHI pomocí lineárního seznamu

Abstraktní datové typy FRONTA

Binární vyhledávací strom pomocí směrníků Miroslav Hostaša L06620

Radomíra Duží L Datový typ množina

Pascal. Katedra aplikované kybernetiky. Ing. Miroslav Vavroušek. Verze 7

Implementace binárního stromu směrníky

Programovací jazyk Pascal

Binární vyhledávací stromy

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Dynamické datové typy a struktury

Předmět: Algoritmizace praktické aplikace

Maturitní otázky z předmětu PROGRAMOVÁNÍ

Čtvrtek 8. prosince. Pascal - opakování základů. Struktura programu:

10 Algoritmizace Příklad 2 Word 2007/ VBA

B3B33ALP - Algoritmy a programování - Zkouška z předmětu B3B33ALP. Marek Boháč bohacm11

B3B33ALP - Algoritmy a programování - Zkouška z předmětu B3B33ALP. Marek Boháč bohacm11

Reprezentace aritmetického výrazu - binární strom reprezentující aritmetický výraz

Sada 1 - Základy programování

Skripta ke školení. Základy VBA. vypracoval: Tomáš Herout. tel:

- znakové konstanty v apostrofech, např. a, +, (znak mezera) - proměnná zabírá 1 byte, obsahuje kód příslušného znaku

Lineární spojový seznam (úvod do dynamických datových struktur)

Datové struktury. alg12 1

Pointery II. Jan Hnilica Počítačové modelování 17

Vyučovací hodina. 1vyučovací hodina: 2vyučovací hodiny: Opakování z minulé hodiny. Procvičení nové látky

Anotace. Pointery. Martin Pergel,

Algoritmizace a programování

Binární vyhledávací strom. Proč binární? Vyhledávání

Více o konstruktorech a destruktorech

Homer. prvky. délka. přední 0 zadní 4. Použití fronty BUS STOP. 3 Lisa. 2 Bart. 4 Maggie. 1 Marge. Grafické znázornění předchozí animace:

dovolují dělení velkých úloh na menší = dekompozice

2 Datové typy v jazyce C

7. OBJEKTOVĚ ORIENTOVANÉ PROGRAMOVÁNÍ

for (int i = 0; i < sizeof(hodnoty) / sizeof(int); i++) { cout<<hodonoty[i]<< endl; } cin.get(); return 0; }

type Obdelnik = array [1..3, 1..4] of integer; var M: Obdelnik;

Časová a prostorová složitost algoritmů

O datových typech a jejich kontrole

Algoritmizace Dynamické programování. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010

Zadání: TÉMA: Zápis algoritmu, čtení textového souboru, porovnání řetězců.

Sada 1 - Základy programování

NMIN102 Programování /2 Z, Zk

Úvod do programování

Základní způsoby: -Statické (přidělění paměti v čase překladu) -Dynamické (přiděleno v run time) v zásobníku na haldě

Programujeme v softwaru Statistica

Programovací jazyk. - norma PASCAL (1974) - implementace Turbo Pascal, Borland Pascal FreePascal Object Pascal (Delphi)

Programování v C++, 2. cvičení

Pracovní listy - programování (algoritmy v jazyce Visual Basic) Algoritmus

Sada 1 - Základy programování

PODPROGRAMY PROCEDURY A FUNKCE

Cílem kapitoly je seznámit studenta se seznamem a stromem. Jejich konstrukci, užití a základní vlastnosti.

Implementace LL(1) překladů

Algoritmy a datové struktury

9. přednáška - třídy, objekty

Binární soubory (datové, typované)

1. Implementace funkce počet vrcholů. Předmět: Algoritmizace praktické aplikace (3ALGA)

Základní způsoby: -Statické (přidělění paměti v čase překladu) -Dynamické (přiděleno v run time) v zásobníku na haldě

6 Příkazy řízení toku

Object Pascal je přísně typový procedurální jazyk, který umožňuje jak strukturované, tak objektově orientované programování.

Test prvočíselnosti. Úkol: otestovat dané číslo N, zda je prvočíslem

Registrační číslo projektu: CZ.1.07/1.5.00/ Elektronická podpora zkvalitnění výuky CZ.1.07 Vzděláním pro konkurenceschopnost

NPRG030 Programování I, 2015/16 1 / :25:32

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

2 Strukturované datové typy Pole Záznam Množina... 4

MAXScript výukový kurz

Datové typy a struktury

Stromy, haldy, prioritní fronty

Konstruktory a destruktory

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Pole a kolekce. v C#, Javě a C++

Algoritmizace a programování

Řídicí struktury. alg3 1

6. Příkazy a řídící struktury v Javě

DUM 07 téma: Proměnné, konstanty a pohyb po buňkách ve VBA

Binární vyhledávací stromy pokročilé partie

Vyhledávací stromy. Slouží jako pomůcka pro organizaci dat umožňující efektivní vyhledávání.

Algoritmizace prostorových úloh

1 PRVOCISLA: KRATKY UKAZKOVY PRIKLAD NA DEMONSTRACI BALIKU WEB 1

int t1, t2, t3, t4, t5, t6, t7, prumer; t1=sys.readint();... t7=sys.readint(); prume pru r = r = ( 1+t 1+t t3+ t3+ t4 t5+ t5+ +t7 +t7 )/ ;

Programování 2 (NMIN102) Soubory. RNDr. Michal Žemlička, Ph.D.

Základní datové struktury

Výčtový typ strana 67

Obecná informatika. Matematicko-fyzikální fakulta Univerzity Karlovy v Praze. Podzim 2012

Anotace. Spojové seznamy, haldy. AVL-stromy, A-B stromy. Martin Pergel,

Pseudonáhodná čísla = algoritmicky generovaná náhrada za náhodná čísla

Aplikovaná informatika. Podklady předmětu Aplikovaná informatika pro akademický rok 2013/2014 Radim Farana. Obsah. Strom

Spojové struktury. Spojová struktura (linked structure):

Implementace aritmetického stromu pomocí směrníků

Sada 1 - Základy programování

ALGORITMIZACE A PROGRAMOVÁNÍ

Programování II. Návrh programu I 2018/19

Knihovna DataBoxLib TXV první vydání prosinec 2010 změny vyhrazeny

Čtvrtek 3. listopadu. Makra v Excelu. Obecná definice makra: Spouštění makra: Druhy maker, způsoby tvorby a jejich ukládání

Anotace. Pointery, dynamické proměnné

Obsah přednášky. programovacího jazyka. Motivace. Princip denotační sémantiky Sémantické funkce Výrazy Příkazy Vstup a výstup Kontinuace Program

Základní pojmy. Úvod do programování. Základní pojmy. Zápis algoritmu. Výraz. Základní pojmy

Struktura programu v době běhu

Náznak ukázky syntaxe a sémantiky pro projekt. 1 Syntaktické prvky. Poslední aktualizace: 8.

VISUAL BASIC. Přehled témat

á ý á á ú ú ř ý ý ů ě ů ř á á á á ě ě š ř ů á ě ě ě ů ř š ý š ě ů ž ář ř ř š ý ář á ě ř á ý ě ů á á á ě á ž ě ě ů ě ý ě ř ě šť Č ý á á ř á ě á ř ý ý á

EVROPSKÝ SOCIÁLNÍ FOND. Úvod do PHP PRAHA & EU INVESTUJEME DO VAŠÍ BUDOUCNOSTI

Transkript:

1. D Y N A M I C K É DAT O V É STRUKTUR Y Autor: Petr Mik Abychom se mohli pustit do dynamických datových struktur, musíme se nejdřív podívat na datový typ ukazatel. 1. D AT O V Ý TYP U K A Z AT E L Datové typy (např. string, integer, char, real ) mají přesně definovanou velikost. Proměnná těchto datových typů je při deklaraci umístěna do konkrétního místa v operační paměti a na tomto místě setrvává po celou dobu své existence. Beze změny zůstávají také jejich deklarované vlastnosti. Těmto proměnným se říká statické. Kromě statických proměnných existují také proměnné dynamické. Od statických proměnných se liší tím, že okamžik jejich vzniku či zániku není dán deklarací, ale zvláštním příkazem pro vytvoření nebo zánik. Chtějme vytvořit dynamickou proměnnou (její místo v operační paměti není předem určeno). Abychom mohli s touto proměnnou pracovat, musíme znát její adresu v operační paměti. Proto musíme nejprve vytvořit statickou proměnu, nazývanou ukazatel, ve kterém se bude uchovávat adresa dynamické proměnné. Velikost ukazatele v operační paměti je 4B. 2. D E K L A R A C E D A T O V É H O T Y P U U K A Z A T E L Deklarujme proměnnou dynamcislo, které bude typu ukazatel. Deklaraci provedeme takto: var dynamcislo: ^real; pozn.: Znak ^ je označením skutečnosti, že proměnná dynamcislo je datového typu ukazatel. Potom můžeme v programu zapsat: new(dynamcislo); tím se vytvoří dynamická proměnná. Chceme-li do této proměnné přiřadit hodnotu, napíšeme dynamcislo^:= 55.1;

tím proběhnou dvě akce: nejprve se zjistí hodnota v proměnné dynamcislo, což je adresa ukazující někam do operační paměti, a poté se na tuto adresu přiřadí zadaná hodnota, pro proměnnou typu real je to 6B. Chceme-li vyhrazený úsek operační paměti uvolnit, zapíšeme příkaz dispose(dynamcislo) tím se onen 6B úsek dán k dispozici, například pro další proměnné. Proměnná dynamcislo, která obsahuje adresu, však zůstává dále k dispozici, její hodnota je však nedefinována. Víme tedy, že ve skutečnosti existují dvě proměnné dynamcislo a dynamcislo^. 3. O P E R A C E N A D D A T O V Ý M T Y P E M U K A Z A T E L Mějme tento zdrojový text: var u,v: ^real; new(u); new(v); u^:= 3.1415926536/2; v:= u; v tomto místě proměnná v nabyla stejné hodnoty jako proměnná u obě ukazují na stejné místo v paměti (na stejnou hodnotu). Protože jsou stejného datového typu, můžeme provést relační operace zjištění rovnosti a nerovnosti pomocí operátorů = a <>. Existuje také vyhrazené číslo nil, což je vlastně hodnota, která říká, že ukazatel neukazuje na žádnou proměnnou. Příklad použití hodnoty nil si uvedeme u algoritmů s dynamickými datovými strukturami. 4. D Y N A M I C K Á DAT O V Á STRUTURA Dynamicky deklarované proměnné, které jsme si ukázali, můžeme přirovnat k proměnným jednoduchých datových typů (obsahují jednu jedinou hodnotu a nijak nesouvisí s jinými proměnnými). Pokud chceme soustředit více údajů do proměnné, použili jsme strukturovaný datový typ (např.: pole, záznam ). Ke strukturovaným proměnným můžeme přirovnat zvláštní struktury dynamických proměnných, které se nazývají seznamy a stromy. Základní vlastností všech seznamů a stromů je existence vazby mezi prvky seznamu nebo stromu. Každý prvek seznamu i stromu má proto dvě části, část datovou a část vazební.

Příklad deklarace: Type UkTypPrvku= ^TypPrvku; TypPrvku= record hodnota: integer; DalsiPrvek: UkTypPrvku; Seznam si můžeme představit jako posloupnost prvků, kde vazba určuje následníka, případně předchůdce, vždy však nejvýše jednoho. To je hlavní rozdíl od stromu, kde se předpokládá vazba k více než jednomu následníkovi. Seznamů a stromů je více druhů, ty se rozlišují podle vlastností datové struktury. 5. L I N E Á R N Í S E Z N A M J E D N O S M Ě R N Ý 6. V L O Ž E N Í P R V K U N A Z A Č Á T E K S E Z N A M U, P R Ů C H O D S E Z N A M E M A J E H O S M A Z Á N Í Tento seznam si můžeme představit jako posloupnost prvků, kde vazba určuje následníka, viz obr. u 1 2 3 4 5 Nil Na obrázku vidíme, že každý seznam má jeden počáteční prvek. Je to ukazatel, který nás odkazuje na první prvek seznamu. Mezi seznamy patří i prázdný seznam. Hodnota ukazatele na prázdný seznam je obvykle nil. Následující příkazy řeší vytvoření prázdného seznamu. Budeme předpokládat deklaraci datového typu UkTypPrvek, viz výše: var začátek, prvek: UkTypPrvku; začátek:= nil; Teď jsme vytvořili prázdný seznam. Další příkazy řeší vložení nového prvku na začátek seznamu. New(prvek); {vytvoření prostoru pro nový prvek}

prvek^.dalsiprvek:= zacatek; začátek:= prvek; end. {vazba mezi prvky} {počáteční ukazatel ukazuje na vytvořený prvek} Důsledkem tohoto jednoduchého postupu vzniká posloupnost prvků seznamu v opačném pořadí, než jsme prvky vytvářeli. Nyní si to vyzkoušíme na jednoduchém příkladu. Program budeme pro lepší přehlednost členit na podprogramy. Type UkTypPrvku= ^TypPrvku; TypPrvku= record hodnota: integer; dalsiprvek: UkTypPrvku; var začátek: UkTypPrvku; cislo: integer; potom si při vytváření formuláře pomocí procedure TForm1.FormCreate(Sender: TObject); přiřadíme začátku seznamu nil zacatek:=nil; procedure vloznovyprvek(var zac: UkTypPrvku; cis: integer); var pr: UkTypPrvku; new(pr); pr^.hodnota:= cis; {zde vkládáme hodnotu} pr^.dalsiprvek:= zac; zac:= pr procedure vypis(zac: UkTypPrvku); while zac <> nil do {průchod lineárním seznamem} memo1.lines.add(inttostr(zac^.hodnota)); zac:= zac^.dalsiprvek; cislo:= strtoint(edit1.text); vloznovyprvek(zacatek, cislo); vypis; {přechod na další prvek} Algoritmus tisku prvků je konkrétním případem obecného algoritmu průchodu lineárním seznamem s provedením nějaké akce. Podmínkou je, aby byl poslední prvek

seznamu odlišitelný od ostatních prvků poslední prvek má vždy hodnotu ukazatele na další prvek nil. Všimněme si parametru zac v proceduře vypis. Uvnitř cyklu se nachází příkaz zac:= zac^.dalsiprvek, což umožňuje přechod na následující prvek v seznamu. Uvnitř procedury se tedy hodnota parametru zac průběžně mění. Protože je však tento parametr deklarován jako parametr volaný hodnotou, změna jeho hodnoty (= hodnota proměnné zacatek v hlavním programu) se do hlavního programu nepřenese. V proměnné zacatek je proto pořád uložena hodnota skutečného začátku seznamu. Když seznam už nebudeme používat, měly bychom uvolnit místo v paměti. Opět použijeme průchod lineárním seznamem. procedure TForm2.FormCreate(Sender: TObject); var pom: UkTypPrvku; while zacatek<>nil then pom:= zacatek; zacatek:= začátek^.dalsiprvek; dispose(pom); 7. H L E D Á N Í P R V K U A V Y Ř A Z E N Í P R V K U Z E S E Z N A M U Při sestavování vyhledávací funkce musíme předem rozhodnout, zda je potřeba získat informaci pouze o výskytu prvku nebo o jeho umístění. function JeCisloVSeznamu (seznam: UkTypPrvku; cislo: integer): boolean; while (seznam<>nil) and (seznam^.hodnota<>cislo) do seznam:= seznam^.dalsiprvek; JeCisloVSeznamu:=seznam<>nil; tato vyhledávací funkce pouze zjišťuje, zda se hledaný prvek v seznamu nachází. Její použití si ukážeme na následujícím příkladu. while seznam<>nil do

cislo:= strtoint(edit1.text); if JeCisloVSeznamu (seznam, cislo) then memo1.lines.add( toto číslo je v seznamu ) else memo1.lines.add( toto číslo není v seznamu ); Naopak výsledkem funkce function Najdi (zac: UkTypPrvku; cis: integer): UkTypPrvku; while (zac<>nil) and (zac.^hodnota<>cis) do zac:= zac^.dalsiprvek; result:= zac; je součastná hodnota proměnné zac (resutl:= zac), tedy adresa prvku, jehož datová část má stejnou hodnotu jako zadané číslo. Přiřazovací příkaz (resutl:= zac) má smysl i v případě, že číslo nebylo nalezeno a cyklus byl ukončen nalezením hodnoty nil v proměnné zac. Tím zajistíme, že funkce Najdi bude mít definovanou hodnotu v každém případě. Vyřazení prvku ze seznamu je ve skutečnosti pouze změna vazby mezi prvky, v tomto případě vyhledaný prvek spojujeme s následníkem následníka. procedure VyradNaslednika(var pr: UkTypPrvku); var pomprvek: UkTypPrvku; if pr^.dalsiprvek<>nil then {zda není prvek posledním prvkem seznamu} pomprvek:= pr^.dalsiprvek; pr^.dalsiprvek:= pr^.dasliprvek^.dalsiprvek; daspose(pomprvek); Pokud bude pr^.dasliprvek=nil, potom pracujeme s posledním prvkem seznamu a ten nemá žádného následníka. Nemá tedy smysl se pokoušet o vyřazení. Proměnnou pomprvek zavádíme jen proto, abychom mohli uvolnit operační paměť, kterou zabírá vyřazovaný prvek. Poněkud komplikovanější situace nastane, budeme-li chtít vyřadit nikoliv následující prvek (jako v předchozím příkladě), ale aktuální prvek, tj. ten, jehož hodnota odpovídá zadanému číslu.

Změna vazby spočívá v tom, že spojíme předchůdce s následníkem, čímž aktuální prvek přeskočíme. Funkce Najdi sice nalezne prvek, který odpovídá zadané hodnotě, ale nejsme schopni jej vyřadit, protože neznáme předchůdce. Musíme tedy vytvořit jinou vyhledávací funkci: function NajdiPredchudce (zac: UkTypPrvku; cis: integer): UkTypPrvku; var předchůdce: uktypprvku; předchůdce:=nil; while (zac<>nil) and (zac^.hodnota<>cis) do {najde předchůdce hledaného čísla} predchudce:= zac; zac:= zac^.dalsiprvek; if zac=nil then result:=nil; else result:=predchudce; Nyní pomocí funkce NajdiPredchdce a prcedury VyradNaslednika můžeme vytvořit program, kterým odebereme právě to číslo, které hledáme. Tělo programu bude vypadat takto:... cislo:= strtoint(edit2.text); hledane:= NajdiPredchudce(zacatek, cislo); if hledane<>nil then VyradNaslednika(hledane); else memo1.lines.add( hledaný prvek nenalezen );... 8. O B E C N É V L O Ž E N Í P R V K U D O S E Z N A M U, U S P O Ř Á D A N Ý L I N E Á R N Í S E Z N A M Doposud používaný proces vkládání prvků do seznamu umožňoval vkládat prvky jen na začátek seznamu. To však je jen jedna možnost vložení prvku do tohoto seznamu. Může nastat situace, při níž vkládáme nový prvek dovnitř seznamu, například při řazení. Algoritmus si ukážeme na proceduře, která vkládá nový prvek za prvek známý. procedure VlozZa(prvek: UkTypPrvku, novy: UkTypPvek);

novy^.dalsiprvek:= prvek^.dalsiprvek prvek^.dalsiprvek:= novy pracujeme jen s vazbami mezi prvky, nyní známý prvek ukazuje na prvek nový, který ukazuje na zbytek seznamu. Jako praktickou ukázku vkládání sestavíme program, jehož účelem je vytvořit uspořádaný lineární seznam z libovolných vstupních hodnot. Program bude kromě hlavního programu obsahovat také již výše uvedenou proceduru VlozZa, a také proceduru VlozNaZacatek a funkci Najdi, které si uvedeme níže. Na konec zavoláme podprogram pro vypsání seznamu. obrázek: Schéma vkládání prvku do uspořádaného lineárního seznamu ukazuje následující u 1 6 w 5 7 12 nil Prvek, jehož hodnota je rovna 5, byl nalezen příslušnou vyhledávací funkcí. Písmenem u je vyjádřen počátek seznamu, písmeno w označuje vkládaný prvek. Hledání prvku obsahuje porovnání čteného čísla s hodnotou aktuálního prvku. Pokud je hodnota prvku menší než přečtené číslo, postupujeme v lineárním seznamu k dalšímu prvku. Nalezená hodnota je tedy ta, která je poslední menší než přečtené číslo a za tuto hodnotu vložíme nový prvek. function Najdi (zac: UkTypPrvku; cis: integer): UkTypPrvku; if zac^.hodnota>cis then result:= nil else while (zac^.dalsiprvek<>nil) and (zac^.dalsiprvek^.hodnota<cis) do zac:= zac^.dalsiprvek;

result:= zac Pokud se stane, že první prvek, který chceme vložit, je menší než první prvek v seznamu, je výslednou hodnotou nil. V hlavním programu potom tyto dvě situace rozlišujeme a podle situace zvolíme vhodnou proceduru pro vložení prvku za prvek (procedura VlozZa) nebo na začátek seznamu (procedura VlozNaZacatek). procedure VlozNaZacatek (var zac: UkTypPrvek, pr: UkTypPrvek); pr^.dalsiprvek:= zac; zac:= pr; Zpátky k programu pro vytvoření uspořádaného lineárního seznamu: Type UkTypPrvku= ^TypPrvku; TypPrvku= record hodnota: integer; dalsiprvek: UkTypPrvku; var usporadany, kamvlozit, vkladanyprvek: UkTypPrvku; zde budou výše deklarované podprogramy a také procedura pro výpis. procedure VlozNaZacatek function Najdi procedure VlozZa procedure TiskniSeznam seznamem. Procedura TiskniSeznam není nic jiného než obyčejné procházení lineárním Potom už následuje hlavní program: new(vkladanyprvek); vkladanyprvek^.hodnota:= strtoint(edit1.text); if usporadany=nil then VlozNaZacatek(usporadany, vkladanyprvek else kamvlozit:= Najdi(usporadany, vkladanyprvek^.hodnota); if kamvlozit=nil then VlozNaZacatek(usporadany, vkladanyprvek)

else VlozZa(kamVlozit, vkladanyprvek); TiskniSeznam(usporadany);