map, multimap - Asociativní pole v C++.

Podobné dokumenty
Množina v C++ (set, multiset).

Vector datový kontejner v C++.

Standardní algoritmy vyhledávací.

Funkční objekty v C++.

Šablony, kontejnery a iterátory

Iterátory v C++. int pole[20]; for (int *temp = pole, temp!= &pole[20]; temp++) { *temp = 0;

Šablony, kontejnery a iterátory

<surface name="pozadi" file="obrazky/pozadi/pozadi.png"/> ****************************************************************************

PB161 Programování v jazyce C++ Přednáška 3

PROGRAMOVÁNÍ V C++ CVIČENÍ

Jazyk C++ II. STL knihovna kontejnery část 1

Pokročilé programování v jazyce C pro chemiky (C3220) Statické proměnné a metody, šablony v C++

PB161 Programování v jazyce C++ Přednáška 3

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

Cvičení z programování v C++ ZS 2016/2017 Přemysl Čech

PB přednáška (26. října 2015)

Standardní algoritmy v C++.

Množina čísel int stl-set-int.cpp

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

Jazyk C++ II. STL knihovna kontejnery část 2

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

Šablony funkcí a tříd (Templates) Genericita

Konstruktory a destruktory

přetížení operátorů (o)

Řetězce. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze. Karel Richta, Martin Hořeňovský, Aleš Hrabalík, 2016

Martin Flusser. Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague. October 17, 2016

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

Jazyk C++ II. Šablony a implementace

PB161 Programování v jazyce C++ Přednáška 10

PB161 Programování v jazyce C++ Přednáška 8

Hornerovo schéma. je algoritmus výpočtu hodnoty polynomu P(x) v bodě x 0. eliminuje výpočet i-té mocniny převodem na postupné násobení.

Pokročilé programování v jazyce C pro chemiky (C3220) Vstup a výstup v C++

PB161 Programování v jazyce C++ Přednáška 10

Více o konstruktorech a destruktorech

PB161 Programování v jazyce C++ Přednáška 6

Dědičnost. Časová náročnost lekce: 3 hodiny Datum ukončení a splnění lekce: 23.března

Mělká a hluboká kopie

Základy C++ I. Jan Hnilica Počítačové modelování 18

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

Prostory jmen. při vkládání několika hlavičkových souborů může vzniknout kolize. logika.h const int x=5; typedef struct {...

přetížení operátorů (o)

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

PB161 Programování v jazyce C++ Přednáška 9

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

Dynamická identifikace typů v C++.

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

for (i = 0, j = 5; i < 10; i++) { // tělo cyklu }

PB161 Programování v jazyce C++ Přednáška 4

C++ Akademie SH. 2. Prom nné, podmínky, cykly, funkce, rekurze, operátory. Michal Kvasni ka. 20. b ezna Za áte níci C++

C++ přetěžování funkcí a operátorů. Jan Hnilica Počítačové modelování 19

PB161 Programování v jazyku C++

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

Základy programování (IZP)

PB161 Programování v jazyce C++ Přednáška 9

Vstupní a vstupní proudy v C++

Digitální učební materiál

PROGRAMOVÁNÍ V C++ CVIČENÍ. Michal Brabec

Zpracoval:

Jazyk C++ I. Šablony 2

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

PB161 Programování v jazyce C++ Přednáška 9

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

PB161 Programování v C++ Proudy pro standardní zařízení Souborové proudy Paměťové proudy Manipulátory

PB přednáška (23. listopadu 2015)

Obsah. Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15

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

PB161 Programování v jazyce C++ Přednáška 1

C++ objektově orientovaná nadstavba programovacího jazyka C

Domácí úkoly Pokročilé programování v C++ LS 2015/2016. NPRG051 Pokročilé programování v C / DÚ

Ukazatele, dynamická alokace

PROMĚNNÉ, KONSTANTY A DATOVÉ TYPY TEORIE DATUM VYTVOŘENÍ: KLÍČOVÁ AKTIVITA: 02 PROGRAMOVÁNÍ 2. ROČNÍK (PRG2) HODINOVÁ DOTACE: 1

Polymorfismus. Časová náročnost lekce: 3 hodiny Datum ukončení a splnění lekce: 30.března

Seznamy a iterátory. Kolekce obecně. Rozhraní kolekce. Procházení kolekcí

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.

termín: utorok :00 (poledne) Cíle: Zadání:

Jazyk C++, některá rozšíření oproti C

Abstraktní datové typy

Úvod do jazyka C. Ing. Jan Fikejz (KST, FEI) Fakulta elektrotechniky a informatiky Katedra softwarových technologií

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

PB161 Programování v jazyce C++ Přednáška 1

Úvod do programování. Lekce 1

8. Načítání a zápis PDB souboru

ZPRO v "C" Ing. Vít Hanousek. verze 0.3

PB161 Programování v jazyce C++ Přednáška 5

STL: standardní knihovna šablon

PB161 Programování v jazyce C++ Přednáška 4

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

Jazyk C++ I. Polymorfismus

Prostory jmen. #include<iostream.h> namespace RadimuvProstor { int secti(int a, int b); class Trida { private: int Atribut; public: void metoda();

PROGRAMOVÁNÍ V C++ URČENO PRO VZDĚLÁVÁNÍ V AKREDITOVANÝCH STUDIJNÍCH PROGRAMECH ROSTISLAV FOJTÍK

Martin Flusser. Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague. December 7, 2016

Algoritmizace prostorových úloh

Chování konstruktorů a destruktorů při dědění

Dědění, polymorfismus

Syntaxe vyjímek. #include <iostream> #include <string> using namespace std; // Trida vyjimek class Vyjimka { private:

Domácí úkoly 2013/14

PB161 Programování v jazyce C++ Přednáška 6

Jazyk C++ II. Výjimky

15. Projekt Kalkulačka

Transkript:

map, multimap - Asociativní pole v C++. Jedná se o asociativní pole. V asociativním poli jsou uloženy hodnoty ve tvaru (klíč,hodnota), kde klíč je vlastně "index" prvku. Klíčem může být libovolný objekt, například string. Šablony map i multimap jsou kontejnery z knihovny STL. Jedná se o asociativní kontejnery. Jak ukládané prvky, tak i klíče musejí mít k dispozici: Bezparametrický konstruktor Musejí být schopny se kopírovat pomocí kopírovacího konstruktoru a operátoru =. Nemohou-li být použity implicitní, musí se operátor = přetížit, a vytvořit kopírovací konstruktor. Destruktor Oba kontejnery mají vnitřní typ value_type. Jedná se o šablonu struktury jménem pair. Tato šablona je přejmenovaná pomocí typedef. Šablona struktury pair je struktura parametrizovaná dvěma typy - klíčem a hodnotou. K vytvoření "páru" můžeme použít konstruktor této šablony, nebo pomocí šablony funkce make_pair. Identifikátory pair a make_pair jsou deklarovány v prostoru jmen std. Jak v šabloně map, tak i v multimap jsou vlastně uloženy tyto "páry" (klíč,hodnota). Ke každé hodnotě se přistupuje pomocí klíče. Rozdíl mezi map a multimap je v tom, že map umožňuje mít pro jeden klíč pouze jednu hodnotu, kdežto multimap může mít pro jeden klíč více asociovaných hodnot. Oba kontejnery jsou deklarovány v hlavičkovém souboru map v prostoru jmen std. Šablona map. Šablona map má tři parametry. Jedná se o typ klíče, typ prvku, a "něco", co porovnává klíče. Třetí parametr má svou implicitní hodnotu, a my jej zatím nebudeme používat. Kdyby někdo chtěl zajistit, aby klíče nebyly porovnávány pomocí relačního operátoru <, zadal by třetí parametr. Třetí parametr může být funkce (ukazatel na funkci), nebo tak zvaný funkční objekt. Funkčními objekty se chci zabývat v budoucnu v samostatné přednášce. K pochopení šablony map nejsou důležité, proto se nimi zde nebudeme zabývat. V dnešní přednášce budeme používat pouze první dva parametry šablon map a multimap. Šablona map má k dispozici konstruktory a destruktor jako všechny ostatní kontejnery. K jednotlivým prvkům se přistupuje pomocí klíčů. Operátor indexování [] má jako svůj parametr také hodnotu klíče. Všechny páry v kontejneru jsou vždy seřazeny podle hodnoty svého klíče.

Podívejme se nyní na některé metody: begin, empty, size, max_size, swap - metody společné pro všechny kontejnery z STL. Vysvětleno v úvodní přednášce o STL. find - parametrem je klíč, metoda vrátí pár (klíč,hodnota), ve kterém klíč odpovídá klíči, který byl zadán jako parametr. Není-li takový pár v kontejneru, metoda vrátí iterátor za poslední prvek (iterátor, který vrací metoda end()). count - parametrem je klíč. Metoda vrátí 1, jestliže v kontejneru existuje hodnota asociována k danému klíči, jinak vrátí 0. Vlastně vrací počet párů s daným klíčem. insert - existují opět 3 varianty této metody (tak jako u šablony vector). pair<iterator, bool> insert(const value_type& x); Jedna možnost je předat metodě insert jako parametr objekt typu value_type. Můžeme jej například vytvořit pomocí šablony funkce std::make_pair. V případě, že v kontejneru neexistuje pár s klíčem daným jako parametr, bude zadaný pár do kontejneru vložen. Jestliže daný klíč již v kontejneru existuje, nestane se nic. Poloha pro nový prvek bude bude vybrán tak, aby kontejner zůstal uspořádán pomocí hodnot klíčů. iterator insert(iterator it, const value_type& x); void insert(const value_type *first, const value_type *last); Další dvě varianty metody insert jsou obdobné jako u šablony vector. Lze pomocí iterátor upřesnit polohu, nebo vložit prvky s jiného kontejneru. Upřesníme-li polohu iterátorem, kontejner si zkontroluje, zda je poloha správná. Kontejner musí být uspořádán podle klíčů. Je-li správná, potom dojde ihned k vložení páru. Ušetří se čas, který by kontejner potřeboval k nalezení správného místa. V opačném případě kontejner nalezne vhodné místo sám. Zachová se tedy, jako by jsme polohu iterátorem vůbec nezadali. erase - existují dvě varianty této metody. Mohu zadat klíč nějaké asociované hodnoty, nebo iterátor udávající polohu páru. Metoda erase odstraní prvek (i s klíčem, tedy celý pár) z kontejneru. Operátor [] - slouží k přístupu k hodnotám pomocí klíčů. Není-li v kontejneru pár s daným klíčem, bude vložen pár s daným klíčem, a hodnotou vytvořenou bezparametrickým konstruktorem. Takové chování nemusí být vždy žádoucí (viz příklad). To je výčet asi nejdůležitějších metod.

Nyní si vše osvětlíme na příkladu: #include <iostream> #include <map> #include <string> int main(int argc, char **argv) // Klic je string, hodnota je int std::map<std::string,int> TelefoniSeznam; // vkladani nejakych hodnot. TelefoniSeznam.insert(std::make_pair(std::string("Dostal"),4578963)); TelefoniSeznam.insert(std::make_pair(std::string("Novak"),12458632)); TelefoniSeznam.insert(std::make_pair(std::string("Hasici"),150)); TelefoniSeznam.insert(std::make_pair(std::string("Policie"),158)); // zobrazeni neboli pristup k nekterych prvku pomoci operatoru [], pomoci klice std::cout << "Hasici " << TelefoniSeznam[std::string("Hasici")] << std::endl; std::cout << "Dostal Radim " << TelefoniSeznam[std::string("Dostal")] << std::endl; // dotaz na telefonni cislo Bonda, ktere neexistuje std::string jmeno("bond"); std::cout << "Bond James "; if (!TelefoniSeznam.count(jmeno)) std::cout << "neni v seznamu." << std::endl; else std::cout << TelefoniSeznam[jmeno] << std::endl; // pouzitim operatoru [] pridam do seznamu Bonda, coz nemusi byt // vzdy zadouci!!! Muze byt lepsi radeji pouzit metodu find std::cout << "Muzete se o tom presvedcit: " << TelefoniSeznam[jmeno] << std::endl; // pokracovani...

// pokracovani // zobrazeni seznamu std::map<std::string,int>::iterator i; for(i = TelefoniSeznam.begin(); i!= TelefoniSeznam.end(); i++) // zobrazeni klic, hodnota. Sablona struktury pair ma dva // atributy: first a second std::cout << i->first << " " << i->second << std::endl; // vymazani prvni polozky a vymazani Novaka TelefoniSeznam.erase(TelefoniSeznam.begin()); TelefoniSeznam.erase(std::string("Novak")); std::cout << std::endl; // zobrazeni polezek seznamu for(i = TelefoniSeznam.begin(); i!= TelefoniSeznam.end(); i++) std::cout << i->first << " " << i->second << std::endl; return 0; Výsledek: Dobře si všimněte, jak se v kontejneru objevil Bond. Použil jsem ho jako parametr pro operátor [].

Šablona multimap. Šablona multimap je asociativní pole, které umožní mít k jednomu klíči asociováno několik hodnot. Práce se šablonou multimap je podobná jako práce se šablonou map. Zaměřím se pouze na rozdíly. První důležitá věc je, že šablona třídy multimap již nemá operátor []. Prvky s daným klíčem lze nalézt pomocí metody find. Tím ale nalezneme pouze jeden (ten první) prvek s daným klíčem. Chceme-li nalézt všechny prvky s daným klíčem, musíme použít metody lower_bound, upper_bound, nebo equal_range. Tyto metody byly i v šabloně map, ale tam neměly snad žádné využití: lower_bound - parametrem je klíč. Vrací iterátor na prvek s nejmenším klíčem, který je větší, nebo roven zadanému klíči. Neexistuje-li takový prvek, vrací iterátor za konec kontejneru ( end() ). iterator lower_bound(const Key& key); const_iterator lower_bound(const Key& key) const; upper_bound - parametrem je klíč. Vrací iterátor na prvek s největším klíčem, který je menší, nebo roven zadanému klíči. Neexistuje-li takový prvek, vrací iterátor za konec kontejneru ( end() ). iterator upper_bound(const Key& key); const_iterator upper_bound(const Key& key) const; equal_range - parametrem je klíč. Vrací dvojici iterátorů (pair - viz příklad níže). První ve dvojici je výsledek volání metody lower_bound. Druhý ve dvojici je výsledek volání metody upper_bound. Metoda equal_range za nás vlastně zavolá tyto dvě metody. pair<iterator, iterator> equal_range(const Key& key); pair<const_iterator, const_iterator> equal_range(const Key& key) const;

Nyní si vytvoříme ukázkový příklad. Bude se jednat o jednoduchou ukázkovou hash tabulku s velice jednoduchou hash funkcí - mod 13. V tabulce budou uloženy čísla int. Jejich klíče budou také typu int. Klíče jsou int pouze pro přehlednost tohoto ukázkového zdrojového textu. Pro úsporu místa by bylo asi lepší mít klíče short int, nebo i char. Hodnota klíče totiž nebude nikdy větší než 12:

#include <iostream> #include <map> using namespace std; typedef multimap<int,int> THashTabulka; int main(int argc, char **argv) THashTabulka Tabulka; THashTabulka::iterator i; int p; // naplneni tabulky a zobrazeni for(p = 39; p >= 0; p--) Tabulka.insert(make_pair(p % 13, p)); cout << "Pocet prvku v tabulce " << Tabulka.size() << endl; for(i = Tabulka.begin(); i!= Tabulka.end(); i++) cout << "(" << i->first << "," << i->second << ")\t"; cout << endl; // zobrazeni poctu polozek s klicem 10 a prvni polozky s cislem 10 cout << "PocetPrvku s klicem 10 je " << Tabulka.count(10) << ". Prvni je: " << (*Tabulka.find(10)).second << endl; // zobrazeni poctu polozek s klicem 5 a zobrazeni polozek s klicem 5 i = Tabulka.find(5); cout << "PocetPrvku s klicem 5 je " << Tabulka.count(5) << endl; for(p = 0; p < Tabulka.count(5); p++,i++) cout << "(" << i->first << "," << i->second << ")\t"; cout << endl; // pokracovani.

// pokracovani // Lepší zpusob prochazeni : zobrazeni prvku s klicem 0 THashTabulka::iterator j = Tabulka.upper_bound(0); cout << "Prvky s indexem 0:" << endl; for(i = Tabulka.lower_bound(0); i!= j; i++) cout << "(" << i->first << "," << i->second << ")\t"; cout << endl; // Asi nejlepší zpùsob je: zobrazeni polozek s klicem 7 pair<thashtabulka::iterator,thashtabulka::iterator> par=tabulka.equal_range(7); cout << "Klici s indexem 7 odpovida:" << endl; for(i = par.first; i!= par.second; i++) cout << i->second << "\t"; cout << endl; return 0; Výsledek: Tolik tedy k asociativním polím. Až se budeme zabývat tématem funkčních objektů v C++, připomeneme si, že i v šablonách map a multimap se dají funkční objekty použít. Je to v případě, kdy nechcete, aby kontejner třídil klíče podle relačního operátoru <, ale podle jiné, Vámi zadané relace.

Cvičení. Cv. 1: Napište program který zachytává znaky z klávesnice, zobrazuje který znak byl kolikrát vybrán. Jde o mapu s klíčem znaku a strukturou mimo jiné o údaji počtu výběru tohoto znaku. Cv. 2 zápočtová samostatná práce č. 2: Vytvořte program, který provádí zkoušení žáků. Program generuje 2 hodnoty pro operaci součet. Pokud žák odpoví hodnou konec, zkoušení je ukončeno. Program pracuje tak, že pokud je výsledek špatně, uloží zadaní do objektu multimap. Objekt multimap má klíč řetězec a to jedna, dve, tri a mnoho a strukturu která obsahuje informace o příkladu. Objekt multimapu se plní jen špatně vypočtenými příklady a to - je li příklad špatně za sebou poprvé (klíč jedna ), podruhé ( dve ), potřetí ( tri ) nebo vícekrát ( mnoho ). Program, pokud multimap obsahuje 3 špatně vypočtené příklady, zadává opakovaně tyto špatně vypočtené příklady s informaci kolikrát byl špatně vypočítán a poslední špatný výsledek. Zadává je od nejvíce špatně vypočtených příkladu po příklady, které byly vypočítané špatně nejméně krát. Pokud špatně vypočítaný příklad je vypočítaný konečně správně, příklad je odstraněn z multimapu. Tvář programu navrhněte tak, aby byly jasné všechny funkce programu. Zápočtová práce bude zdrojem pro zkoušku, proto napište program tak, aby jste ho použili při zkoušce. Termín záleží na Vás, práci převezmu ukázkou na cvičení (ne na přednášce ani na zkoušce!!!). Pokud zadání není jasné, přemýšlejte a udělejte to podle sebe tak, aby byl program použitelný a splňoval zadání.