Abstraktní datové typy

Slides:



Advertisements
Podobné prezentace
Standardní knihovní funkce pro práci s textovými řetězci
Advertisements

ŘÍDÍCÍ STRUKTURY - PODMÍNKY
Počítače a programování 1 Přednáška 13 Jiří Šebesta.
Tabulky v MS ACCESS Autorem materiálu a všech jeho částí, není-li uvedeno jinak, je Mgr. Jiří Novák.
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 –
Přednáška 11 Jiří Šebesta
Programování 2 Cvičení 5.
JUI - 3. přednáška Zpracování seznamů, predikátové a vyhodnocovací funkce RNDr. Jiří Dvořák, CSc.
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.
10. Dynamické datové struktury
Spojové struktury Spojová struktura ( linked structure ):
Zásobník (LiFo) Fronta (FiFo)
BLIŽŠÍ POHLED NA TŘÍDY, DĚDIČNOST - úvod
Programování v C++ Cvičení.
Principy překladačů Mezikód Jakub Yaghob.
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.
A1PRG - Programování – Seminář Ing. Michal Standardní knihovní funkce pro práci se soubory 13 Verze
OSNOVA: a) Řetězce v C b) Funkce stdio.h pro řetězce c) Funkce string.h pro řetězce d) Příklad Jiří Šebesta Ústav radioelektroniky, FEKT VUT v Brně Počítače.
A1PRG - Programování – Seminář Ing. Michal Operátory (2. část) 4 Verze
TI 7.1 NEJKRATŠÍ CESTY Nejkratší cesty - kap. 6. TI 7.2 Nejkratší cesty z jednoho uzlu Seznámíme se s následujícími pojmy: w-vzdálenost (vzdálenost na.
Algoritmy a programovací techniky
Algoritmy vyhledávání a řazení
A1PRG - Programování – Seminář Ing. Michal Ukazatele a pole 10 Verze
Další abstraktní datové typy
Ukázka odstranění rekurze Přemysl Tišer
JavaScript Podmínky, cykly a pole.
Cvičení.
OSNOVA: a)Programování se soubory b)Záloha databáze v souboru c) Příklady Jiří Šebesta Ústav radioelektroniky, FEKT VUT v Brně Počítače a programování.
Datové typy a struktury
Spojové struktury BI-PA1 Programování a algoritmizace 1, ZS
STROMY Datová struktura sestávající z uzlů
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.
Algoritmizace a programování Textové soubory - 13 Mgr. Josef Nožička IKT Algoritmizace a programování
Kompresní algoritmus LZW Dokumentografické informační systémy.
Databázové systémy Informatika pro ekonomy, př. 18.
STRING A UKAZATELE. Co to je řetězec? Řetězec v Javě je samostatný objekt. Je konstantní, co znamená, že jednou vytvořený řetězec nelze změnit. Chceme-li.
Vazby dynamických proměnných,databázové systémy Přednáška č. 10.
Ukazatele, řetězce Přednáška č. 3. Ukazatele  Ukazatel (pointer) – typ o velikosti 4 bajty (v 32bit. systémech) pro uložení adresy objektu na který ukazuje.
Soubory BI-PA1 Programování a algoritmizace 1, ZS Katedra teoretické informatiky © Miroslav Balík Fakulta informačních technologií České vysoké.
Jazyk C A0B36PRI - PROGRAMOVÁNÍ Část II.
Vícerozměrná pole (1) Jazyk C povoluje, aby pole mělo více rozměrů (dimenzí) než jeden Z vícerozměrných polí bývá nejčastěji použí-váno pole dvourozměrné.
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:
Programování OPERÁTOR SIZEOF, FUNKCE, POLE JAKO PARAMETRY FUNKCÍ ERIK KRÁL.
Složitost algoritmu Vybrané problémy: Při analýze složitosti jednotlivých algoritmů často narazíme na problém, jakým způsobem vzít v úvahu velikost vstupu.
Typ struktura (1) Datový typ struktura (struct) je agrego-vaný heterogenní datový typ Jedná se o skupinu několika proměnných, které mohou mít různé datové.
Ú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ícerozměrná pole (1) Jazyk C povoluje, aby pole mělo více rozměrů (dimenzí) než jeden Z vícerozměrných polí bývá nejčastěji použí-váno pole dvourozměrné.
Výukový materiál zpracován v rámci projektu
Programovací jazyk C++
Y36PJC Programování v jazyce C/C++
Číslicová technika.
Abstraktní datové typy
Vzorové řešení zápočtového testu
Programování 2. hodina RNDr. Jan Lánský, Ph.D.
Programování v jazyce C++
Úvod do programování 11. hodina
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)
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.
ALG 07 Selection sort (Select sort) Insertion sort (Insert sort)
Fronta (1) Dynamická datová struktura typu FIFO (First In First Out)
ZAL – 7. cvičení 2016.
Union neboli sjednocení Bitová pole
Algoritmizace a datové struktury (14ASD)
Funkce s proměnným počtem parametrů
Algoritmizace a datové struktury (14ASD)
Transkript prezentace:

Abstraktní datové typy

Abstraktní datové typy (ADT) datová struktura + operace nad touto strukturou jsou většinou dynamické velikost (počet prvků) se dynamicky mění vkládání výběr prvků

ADT spojový seznam fronta zásobník množina strom obecný graf budeme probírat samostatně

Spojový seznam určen pro dynamický seznam (lexikon), kde není znám počet prvků seznamu a jejich počet se často mění (vkládání, mazání) např. v MS Windows je takto uložen seznam ovladačů sdílejících jeden vektor přerušení

Spojový seznam používá se také pro uložení obecného grafu 3 1 3 konec zacatek 3 1 3

implementace v C: typedef struct TPolozka { int prvek; TPolozka *dalsi; } TPolozka; typedef struct { TPolozka *zacatek; TPolozka *konec; } TSeznam; pokud se při deklaraci struktury odkazujeme na ni, napíšeme jméno ještě před „{“

TSeznam sez1; void Init(TSeznam *seznam) { seznam -> zacatek = NULL; seznam -> konec = NULL; }

Vložení na konec seznamu dynamicky vytvořím novou položku (ukazatel na další položku nastavím na NULL) konec zacatek 3 5 1 3 nova

Vložení na konec seznamu ukazatel dalsi u posledního prvku seznamu nastavím na novou položku konec zacatek 3 1 3 5 nova

Vložení na konec seznamu posunu ukazatel na konec seznamu konec zacatek 3 1 3 5 nova Pozor, vkládám-li do prázdného seznamu

void Vloz_na_konec(TSeznam *seznam, int cislo) { TPolozka *nova; nova = (Tpolozka*)malloc(sizeof(Tpolozka)); nova -> prvek = cislo; nova -> dalsi=NULL; if (seznam -> zacatek != NULL) seznam -> konec -> dalsi = nova; seznam -> konec = nova; } else { seznam -> konec = nova; seznam -> zacatek = nova; }

Vložení do seznamu za prvek dynamicky vytvořím novou položku prvek konec zacatek 3 1 3 5 nova

Vložení do seznamu za prvek prováži nový prvek se seznamem prvek konec zacatek 3 1 3 5 nova

Obousměrný spojový seznam položka obsahuje ukazatel na předchůdce i následníka zacatek konec 3 1 3

Úkol naimplementujte spojový seznam (jedno-směrně nebo obousměrně vázaný), do kterého se ukládají jména a telefonní čísla naimplementujte tyto procedury a funkce: inicializace prázdného seznamu test, zda je seznam prázdný vložení záznamu na konec seznamu vložení záznamu za prvek (parametrem je ukazatel na prvek, za který se vkládá, a nové jméno a telefonní číslo)

hledání záznamu (podle jména i telef hledání záznamu (podle jména i telef. čísla) - vrací ukazatel na záznam, pokud není v seznamu, vrací NULL zjištění ukazatele na první záznam zjištění ukazatele na následující záznam výmaz prvku (parametrem je ukazatel na existující prvek, který se má vymazat) zrušení celého seznamu napište jednoduchou konzolovou aplikaci pro otestování implementace seznamu; data zadávejte z klávesnice nemusíte využít všechny funkce

Fronta datová struktura typu FIFO First In - First Out prvky se odebírají v pořadí, jak byly vkládány

Možné implementace jako spojový seznam polem pevné délky „neomezená“ velikost fronty (omezená pouze velikostí dostupné paměti) operace vložení prvku znamená vložení prvku na konec seznamu operace výběr prvku je výběr z čela fronty polem pevné délky fronta s omezenou velikostí implementuje se jako tzv. kruhová fronta

Implementace pomocí spoj. seznamu fronta reprezentována ukazatelem na čelo fronty a poslední prvek ve frontě prvek fronty nese hodnotu a ukazatel na další prvek ve frontě

typedef struct TPrvek { int x; TPrvek *dalsi; } TPrvek; typedef struct { TPrvek *celo; TPrvek *konec; } TFronta;

celo konec NULL

celo konec NULL vloz(3)

3 celo konec vloz(3)

3 celo konec vloz(3) vloz(5)

3 5 celo konec vloz(3) vloz(5)

3 5 celo konec vloz(3) vloz(5) vloz(10)

3 5 10 celo konec vloz(3) vloz(5) vloz(10)

3 5 10 celo konec vloz(3) vloz(5) vloz(10)

3 5 10 celo konec vloz(3) vloz(5) vloz(10) vyjmi() – vrátí hodnotu z čela fronty - 3

5 10 celo konec vloz(3) vloz(5) vloz(10) vyjmi() – vrátí hodnotu z čela fronty - 3

5 10 celo konec vloz(3) vloz(5) vloz(10) vyjmi() – vrátí hodnotu z čela fronty - 3 vloz(8)

5 10 8 celo konec konec vloz(3) vloz(5) vloz(10) vyjmi() – vrátí hodnotu z čela fronty - 3 vloz(8)

eventuálně TFronta *init() Operace nad frontou void init(TFronta *f), eventuálně TFronta *init() inicializace, vytvoří prázdnou frontu int je_prazdna(TFronta *f) testuje na prázdnou frontu void vloz(TFronta *f, int prvek) vloží prvek na konec fronty int vyjmi(TFronta *f) vyjme prvek z čela fronty void zrus(TFronta *f)

int vyjmi(TFronta *f) { int prvek; TPrvek *pom; if (f->celo == NULL) return -1; prvek = f->celo->x; pom = f->celo; f->celo = f->celo->dalsi; free(pom); return prvek; }

odstranění problému je ve správném používání knihovních funkcí spoléhat se na návratovou hodnotu -1, pokud je fronta prázdná, není nejlepší řešení nepoznám, zda byla vyjmuta -1 nebo byla prázdná fronta lépe by bylo např. nastavovat chybovou proměnnou odstranění problému je ve správném používání knihovních funkcí před každým voláním funkce vyjmi() aplikace otestuje, zda není fronta prázdná např. while (!je_prazdna(&f))

Implementace pomocí pole pevné délky fronta je reprezentována polem a indexem čela a konce fronty fronta má pevnou délku a je implementována jako kruhová (modulo délka pole) je nutné implementovat ještě dotaz, zda je fronta plná

Fronta délky n = 3 1 2 celo: konec: prázdná plná

Fronta délky n = 3 1 2 celo: konec: prázdná plná vloz(3)

Fronta délky n = 3 1 2 celo: 3 konec: 1 prázdná plná vloz(3)

Fronta délky n = 3 1 2 celo: 3 konec: 1 prázdná plná vloz(3) vloz(5)

Fronta délky n = 3 1 2 celo: 3 5 konec: 2 prázdná plná vloz(3) vloz(5)

Fronta délky n = 3 3 5 1 2 celo: konec: 2 prázdná plná vloz(3) vloz(5) 1 2 celo: 3 5 konec: 2 prázdná plná vloz(3) vloz(5) vyjmi() – vrátí hodnotu z čela fronty - 3

Fronta délky n = 3 3 5 1 2 celo: 1 konec: 2 prázdná plná vloz(3) 1 2 celo: 1 3 5 konec: 2 prázdná plná vloz(3) vloz(5) vyjmi() – vrátí hodnotu z čela fronty - 3

Fronta délky n = 3 3 5 1 2 celo: 1 konec: 2 prázdná plná vloz(3) 1 2 celo: 1 3 5 konec: 2 prázdná plná vloz(3) vloz(5) vyjmi() – vrátí hodnotu z čela fronty - 3 vloz(8)

Fronta délky n = 3 3 5 8 1 2 celo: 1 konec: prázdná plná vloz(3) 1 2 celo: 1 3 5 8 konec: prázdná plná vloz(3) vloz(5) vyjmi() – vrátí hodnotu z čela fronty - 3 vloz(8)

Fronta délky n = 3 3 5 8 1 2 celo: 1 konec: prázdná plná vloz(3) 1 2 celo: 1 3 5 8 konec: prázdná plná vloz(3) vloz(5) vyjmi() – vrátí hodnotu z čela fronty - 3 vloz(8) vloz(10)

Fronta délky n = 3 10 5 8 1 2 celo: 1 konec: 1 prázdná plná vloz(3) 1 2 celo: 1 10 5 8 konec: 1 prázdná plná vloz(3) vloz(5) vyjmi() – vrátí hodnotu z čela fronty - 3 vloz(8) vloz(10)

index celo ukazuje na prvek pole na čele fronty, který bude odebrán index konec ukazuje na prvek v poli, kam se zapíše nový prvek pokud se indexy celo a konec rovnají, je fronta buď plná nebo prázdná podle rovnosti indexů není možné rozlišit stav fronty musím tedy tyto stavy uchovávat zvlášť pravidlo: pokud se po přidání prvku indexy rovnají, je fronta plná (obdobně: prázdná)

typedef struct { int *pole; int n; /* velikost pole */ int celo, konec; int plna, prazdna; } TFronta2; int init(TFronta2 *f, int vel) { f->prazdna = 1; f->plna = 0; f->n = vel; f->celo = f->konec = 0; f->pole = (int*)malloc(sizeof(int)*vel); if(f->pole!=NULL) return 1; return 0; }

int je_prazdna(TFronta2 *f) { return f->prazdna; } int vloz(TFronta2 *f, int prvek) if (!f->plna) f->prazdna = 0; f->pole[f->konec]=prvek; f->konec = (f->konec+1)% f->vel; if (f->konec == f->celo) f->plna=1; return 1; return 0;

void zrus(TFronta2 *f) { free(f->pole); } Poznámka: implementace pomocí pole, které by se zvětšovalo dynamicky při zaplnění fronty, by byla mírně komplikovaná. Proč?

K čemu se dá fronta jako ADT využít: fronta událostí v diskrétních simulačních systémech dopravy počítačových sítí číslicových systémů systémů hromadné obsluhy - fronta zákazníků algoritmy procházení grafu do šířky

Zásobník (Stack) datová struktura typu LIFO Last In - First Out nejprve se vybírá prvek, který byl vložen na vrchol (top) zásobníku jako poslední operace: PUSH (uložení hodnoty na vrchol zásobníku) POP (odebrání hodnoty z vrcholu zásobníku)

někdy bývá implementována také operace TOP zjištění hodnoty na vrcholu zásobníku bez odebrání prvku PUSH POP vrchol

Možné implementace na principu spojového seznamu „neomezená“ velikost zásobníku (omezená pouze velikostí dostupné paměti) operace vložení prvku znamená vložení prvku na konec seznamu operace výběr prvku je výběr z konce seznamu polem (pevné nebo proměnné délky) kruhová implementace není potřebná

Implementace na principu spojového seznamu zásobník reprezentován ukazatelem na vrchol zásobníku prvek nese hodnotu a ukazatel na předchozí prvek v zásobníku

typedef struct TPrvek { int x; TPrvek *predch; } TPrvek; typedef struct { TPrvek *vrchol; } TZasob;

2 4 1 vrchol vrchol vrchol NULL vloz(2) vloz(4) vloz(1) vyjmi() – vyjme a vrátí hodnotu z vrcholu zásobníku - 1 vloz(1)

Operace nad zásobníkem void init(TZasob *z), eventuálně TZasob *init() inicializace, vytvoří prázdný zásobník int je_prazdny(TZasob *z) test na prázdný zásobník void push(TZasob *z, int prvek) vloží prvek na vrchol zásobníku int pop(TZasob *z) vyjme prvek z vrcholu zásobníku void zrus(TZasob *z)

TZasob* init() { TZasob *zas =(TZasob*)malloc(sizeof(TZasob)); zas->vrchol = NULL; return zas; } int pop(TZasob *z) int prvek; TPrvek *pom; if (z->vrchol != NULL) prvek = z->vrchol->x; pom = z->vrchol->predch; free(z->vrchol); z->vrchol = pom; return prvek; return -1;

Použití zásobníku ( v této implementaci): TZasob *zas; zas = init(); push(zas,3); push(zas,4); pop(zas); zrus(zas); free(zas);

Implementace pomocí pole obdobně jako fronta implementace je snazší není třeba implementovat „kruhově“ stačí index na vrchol zde je efektivní i implementace s dynamicky se měnící velikostí pole při přidávání prvku

K čemu se dá zásobník jako ADT využít: obrácení pořadí příchozích dat ukládání dat při eliminaci rekurze algoritmy procházení grafu do hloubky

Množina jazyk C neobsahuje datový typ množina Požadavek: implementovat množinu takovým způsobem, aby operace vložení a vyjmutí prvku, testu, zda je prvek v daném množině, měly operační složitost O(1) – konstantní prvek je v množině obsažen „pouze jednou“

běžně se množina reprezentuje bitovým polem prvek s indexem i je prvkem množiny, je-li bit nahozen (tzv. charakteristická funkce) tato reprezentace umožňuje snadnou implementaci operací: vložení prvku nahozením bitu pomocí operace or vyjmutí prvku nulováním bitu pomocí operace and test na existenci prvku pomocí operace and vytvoření doplňku pomocí operace negace sjednocení pomocí operace or atd.

protože je velikost paměti počítače konečná, musí být i univerzum konečné implementaci množiny si budeme demonstrovat na množině ASCII znaků

počet ASCII znaků je 256 Poznámka: bitové pole musí mít 256 bitů, tj. 256/8 = 32 bajtů (slabik) typedef struct { unsigned char pole[32]; } TMnozZnaku; Poznámka: efektivnější by bylo použít pole typu int o velikosti 256/(sizeof(int)*8), z pedagogických důvodů použijeme typ char, kde je velikost pole dána konstantou

operace vyprázdnění množiny představuje vynulování všech prvků pole void vyprazdni(TMnozZnaku *m) { memset(m->pole,0,32); } Doplněk množiny doplněk množiny vytvoříme bitovou negací celého pole

je třeba nastavit příslušný bit void doplnek(TMnozZnaku *m) { for(int i=0;i<32;i++) m->pole[i] = ~(m->pole[i]); } Vložení prvku je třeba nastavit příslušný bit pomocí operace logického součtu s konstantou pro výpočet adresy nastavovaného bitu musíme vytvořit mapovací funkci

Příklad mapovací funkce - tabulka kód znaku slabika bit ve slabice 1 7 8 9

adresa slabiky sl = i / 8 adresa bitu ve slabice bit = i % 8 celočíselné dělení číslem 8 sl = i / 8 adresa bitu ve slabice zbytek po celočíselném dělení číslem 8 bit = i % 8 s příslušným bitem ve slabice budeme pracovat pomocí masky, kterou získáme operací posuvu konstanty 1 o počet bitů, který je roven adrese bitu ve slabice

void vloz(TMnozZnaku *m, unsigned char znak) { int sl = znak / 8; unsigned char maska = 1 << (znak % 8); m->pole[sl] |= maska; } Vyjmutí prvku při vyjímání prvku je maska negována a provádí se operace logického součinu (and, &)

operace logického součinu nad bitovými poli obou množin Průnik dvou množin operace logického součinu nad bitovými poli obou množin void doplnek(TMnozZnaku *m1, TMnozZnaku *m2, TMnozZnaku *m3) { for(int i=0;i<32;i++) m3->pole[i] = m1->pole[i] & m2->pole[i]; }

Jakou použijeme operaci při implementaci sjednocení dvou množin? logický součet Jak bude vypadat testování přítomnosti prvku v množině? if (m->pole[sl] & maska != 0)

pokud je univerzum velké nebo nelze prvkům přiřadit indexy pole, pak je nutné množinu implementovat méně efektivně binárním stromem se operací hledání se složitostí log2n, kde n je počet uzlů stromu (aktuální počet prvků množiny) musí být definováno uspořádání na univerzu, tj. je nutné umět porovnat dva prvky a rozlišit, který je menší, jinak je nutné použít neuspořádané pole prvků nebo spojový seznam