Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!
Zadejte Vaši e-mailovou adresu:
Kamarád fotí rád?
Přihlas ho k odběru fotomagazínu!
Zadejte e-mailovou adresu kamaráda:
C/C++
Množina v C++
26. listopadu 2001, 00.00 | Dnes si povíme něco o množině a multimnožině v C++. Množina je datová struktura, ve které jsou uloženy prvky. V množině, na rozdíl od multimnožiny, nesmí být dva stejné prvky. Nad množinou lze provádět různé operace. Vše je součástí STL jazyka C++.
Dnes si povíme něco o množině a multimnožině v C++. Množina je datová struktura, ve které jsou uloženy nějaké prvky. V množině nesmí být dva stejné prvky. Naopak multimnožina může obsahovat i stejné prvky. Nad množinou lze provádět množinové operace jako jsou například sjednocení a průnik. Pro množinu a multimnožinu existují v C++ šablony set a multiset.
Šablony set a multiset jsou setříděné asociativní kontejnery. Na rozdíl od šablon map a multimap v nich nejsou uloženy dvojce (klíč, hodnota), ale jsou zde uloženy pouze klíče. O kontejnerech map a multimap jsem se zmiňoval ve svém předchozím článku Asociativní pole v C++.
MnožinaMnožina je datová struktura ve které jsou uloženy jednotlivé prvky. Prvky v množině nesmí být stejné. Množina je v C++ reprezentována šablonou set. Šablona set má jeden povinný parametr, který udává typ prvků v množině, a jeden nepovinný parametr, který udává způsob, jakým se budou prvky v množině porovnávat. Nezadáme-li druhý parametr, bude se používat operátor <. Druhým parametrem může být ukazatel na funkci, nebo tak zvaný funkční objekt. Prozatím nebudeme druhý parametr používat. Příští článek bude na téma funkční objekty v C++, potom si povíme něco více o těchto možnostech. Jak je zatím vidět, šablona set se přece jenom trochu liší od množiny, jakou známe z matematiky. Prvním rozdílem je, že v šabloně set mohou být uloženy pouze prvky stejného typu. Mohou zde být i instance různých tříd, ale tyto třídy musejí mít stejného předka (musejí být odvozeny ze stejné třídy). Druhý zásadní rozdíl je v tom, že pro prvky v množině jsou vždy seřazené. Musí být tedy definováno porovnání pomocí operátoru <, nebo jiné porovnání (které se zadá právě tím druhým, nepovinným parametrem). Důležitý je fakt, že je nutné, aby prvky v kontejneru byly seřazeny podle nějaké relace. Kontejner totiž setřídění prvků využívá při vyhledávání a ukládání, kdy použije rychlejší algoritmus.
Šablona set má metody velmi podobné jako šablona map z minulého článku. Pro vkládaní prvků zde existují metody insert. Pro odstranění prvků zase erase. Existují zde metody begin a end pro práci s iterátory atd... Myslím, že nemá smysl zde význam těchto metod znovu vypisovat. Všechny jsou popsány v mých předchozích článcích. Prvky, které se budou do množiny ukládat musejí být schopny vytvářet kopie pomocí kopírovacího konstruktoru, a operátoru =. Budeme-li chtít zjistit, jestli se nějaký prvek nachází v množině použijeme metodu count, která vrátí 0, jestliže prvek v množině není, jinak vrátí 1. Tato metoda vlastně vrací počet prvků v množině, což je 0, nebo 1. U multimnožiny může vrátit 0, nebo celé kladné číslo. V souvislosti s množinou bych ale chtěl upozornit na některé množinové operace, které jsou v STL implementovány. V STL jsou tak zvané standardní algoritmy, což jsou šablony funkcí pracujících s kontejnery. Standardním algoritmům se chci věnovat v, samostatném článku. Dnes si v souvislosti s množinou ukážeme pouze 4 algoritmy - množinové operace.
Operace nad množinouPrůnik množin A a B je množina, jejíž prvky jsou v A a zároveň v B. Sjednocení množin A a B je množina, jejíž prvky jsou v A, nebo v B. Množinový rozdíl množin A a B je množina, jejíž prvky jsou v A, a zároveň nejsou v B. Symetrická diference dvou množin je množina, která je Sjednocení(A,B) - Průnik(A,B), kde symbol - značí množinový rozdíl. Snad není tento zápis moc matoucí, ale já si vůbec nevím rady s tím, jak napsat v HTML symboly pro množinové operace.
operace | algoritmus |
průnik | set_intersection |
sjednocení | set_union |
množinový rozdíl | set_difference |
symetrická diference | set_symmetric_difference |
Všechny algoritmy jsou šablony funkcí. Všechny šablony mají 3 parametry. První dva
jsou typy vstupních iterátorů obou množin. Třetí parametr je typ výstupního iterátoru výsledku.
Každá funkce má 5 parametrů. Nejlépe bude napsat deklaraci jedné z nich:
template<class InputIterator_1, class InputIterator_2, class OutputIterator >
OutputIterator set_union(InputIterator_1 zacatekPrvniho, InputIterator_1 konecPrvniho, InputIterator_2 zacatekPrvniho,
InputIterator_2 konecPrvniho, OutputIterator zacatekVysledku);
První dva parametry funkce udávají
začátek a konec první množiny. Třetí a čtvrtý parametr udává začátek a konec druhé množiny. První a druhá dvojce parametrů
nejsou stejného typu. Znamená to, že nemusíme provádět sjednocení pouze množin (set),
ale i jiných kontejnerů. Ale pokud použijeme jiné kontejnery, musejí být setříděné. Posledním parametrem je výstupní
iterátor výsledku. Dalším důležitým algoritmem je algoritmus includes, který určí, zda jedna
množina je podmnožinou druhé. Šablona includes má 2 parametry. Jsou to typy vstupních
iterátorů první a druhé množiny. Parametry funkce jsou 4. Začátek a konec obou množin. Všechny tyto algoritmy jsou deklarovány v
hlavičkovém souboru algorithm v prostoru jmen std.
Nejlépe bude, ukážeme-li si příklad.
|
V článku jsem použil zmiňované množinové operace. Také jsem ukázal jak zjistit, zda nějaký
prvek náleží do množiny, nebo ne. Šablona set má metody
begin a end vracející konstantní iterátory.
Konstantní iterátor nelze použít jako výstupní, proto nemůže být pátým parametrem funkcí set_....
parametr vysledek.begin(). Kdybych pracoval s kontejnerem, který nemá
metodu begin pouze konstantní (viz další příklad) musel bych řešit další problém.
Musel bych mít ve výsledném kontejneru vytvořeno místo pro výsledné prvky. Abych se vyhnul těmto problémům použil
jsem adaptér jménem insert_iterator. Jedná se o šablonu třídy. Parametrem šablony
je typ kontejneru, do kterého se bude iterátor "odkazovat". Parametry konstruktoru jsou konkrétní instance kontejneru,
a pozice v kontejneru, na kterou se bude zapisovat. Takto vytvořený objekt se pro své okolí jeví jako výstupní
iterátor. Může se kdykoliv jako výstupní iterátor použít. Zavolá-li se pro něj operátor = ,tedy zapisuje-li se na
danou pozici, objekt třídy insert_iterator vloží do "svého" kontejneru nový prvek
pomocí metody kontejneru insert. Tím vytvoří v kontejneru místo pro nový prvek, a
na toto místo nový prvek zapíše. Všechna tato činnost je zapouzdřena v metodě
insert_iterator::operator=(const typename Container::value_type& novaHodnota),
a uživatel třídy se o ní nemusí starat. Container je parametr šablony, value_type
je typ prvků v kontejneru.
V mém druhém příkladě
tento adaptér schválně nepoužiji, abych ukázal jeho výhody. Ještě jen musím dodat, že existují i další, podobné
adaptéry, které jsem zde mohl použít. Adaptér insert_iterator vkládá do kontejneru
vždy na pozici udanou parametrem v konstruktoru. Dále existují back_insert_iterator, který vkládá
vždy na konec kontejneru, nebo front_insert_iterator, který vkládá vždy na začátek kontejneru.
Ale u setříděných kontejnerů nehraje žádnou roli poloha, na kterou se ukládá, protože prvek bude vložen vždy na své místo
dané uspořádáním. Proto je jedno jaký adaptér jsem zvolil pro náš příklad. Všechny zmiňované adaptéry jsou deklarovány v
hlavičkovém souboru iterator v prostoru jmen std.
Práce s multimnožinou je obdobná jako práce s množinou. Multimnožina může obsahovat více stejných prvků. Pomocí metody count zjistíme nejen to, zda prvek v množině je, ale také kolikrát v dané množině je. Přejděme rovnou na příklad. Jeden ze způsobu jak najít nejvyššího společného dělitele dvou čísel je rozložit obě čísla na součin prvočísel. Každý rozklad je vlastně multimnožina, a součin prvků jejich průniků je výsledek. Všimněte si, jaké problémy přináší, když se pokusím nepoužít adaptér vkládací iterátor.
|
Příště se podíváme na funkční objekty v C++.
Obsah seriálu (více o seriálu):
- Základy OOP v C++: Od C k C++
- Základní pojmy objektově orientovaného programování
- Vytváření tříd, instance třídy, zasílání zpráv v C++
- Vytváření instancí - konstruktory, destruktory
- Kopírovací konstruktor v C++
- Jednoduchá dědičnost v C++
- Časná versus pozdní vazba - úvod do polymorfismu v C++
- Polymorfismus - dokončení
- Vícenásobná dědičnost v C++
- Vícenásobná dědičnost v C++ - opakovaná dědičnost
- Vícenásobná dědičnost v C++ - volání konstruktorů a destruktorů
- Přetěžování operátorů v C++ 1.díl
- Přetěžování operátorů v C++ 2. díl
- Vstupní a výstupní operace pomocí datových proudů v C++
- Přetěžování operátorů << a >> pro datové proudy v C++
- Neformátovaný vstup a výstup v C++
- Paměťové proudy v C++
- Prostory jmen v C++
- Řetězce v C++
- Výjimky v C++
- Výjimky v C++ - výjimky tvoří dědičnou hierarchii
- Výjimky v C++ - dokončení
- Dynamická identifikace typů v C++
- Přetypování v C++
- Problémy s typy při vícenásobné dědičnosti
- Šablony funkcí v C++
- Šablony datových typů v C++
- Vnitřní typy u parametrů šablon, vnořené šablony v C++
- Pole s libovolným intervalem indexování v C++
- Datové kontejnery v C++ - Úvod do STL
- Vector - datový kontejner v C++
- Iterátory v C++
- Šablona vector v C++ a iterátory
- Asociativní pole v C++
- Množina v C++
- Funkční objekty v C++
- Standardní funkční objekty v C++
- Úvod do standardních algoritmů v C++
- Kopírovací a přesouvací algoritmy v C++
- Vyhledávací algoritmy v C++
- Skenovací (prohlížecí) algoritmy v C++
- Transformační algoritmy v C++
- Řadící algoritmy v C++
- Halda v C++
- Standardní algoritmy v C++ - dokončení
- Automatické ukazatele v C++
- Inteligentní ukazatel - čítač referencí v C++
- Použití čítače referencí v C++
- Kopírování velkých objektů v C++
- Řízené kopírování prvků v poli v C++
- Dokončení seriálu objektově orientované programování v C++
-
25. listopadu 2012
-
30. srpna 2002
-
10. října 2002
-
4. listopadu 2002
-
12. září 2002
-
25. listopadu 2012
-
28. července 1998
-
31. července 1998
-
28. srpna 1998
-
6. prosince 2000
-
27. prosince 2007
-
4. května 2007