Gyakorló feladatok (10. hét)
Fontosabb kulcsszavak, fogalmak
- Standard Template Library (STL)
- Tárolók, tárolók műveletei
- Sorozattárolók
- Asszociatív tárolók
- Generikus algoritmusok
- Iterátorok
Feladatok megoldásokkal
- Ismételjük át sorozattárolók közös metódusait és az std::vektor speciális metódusait az az STL összefoglaló alapján: http://infocpp.iit.bme.hu/sites/default/files/proga2/stlsummary.pdf! A közös metódusok hasonlítanak a korábban készített gyak::Array tárolónk metódusaihoz. A hasonlóság nem véletlen!
- Magától értetődő, de talán mégis érdemes megnézni, hogy többdimenziós vektort (mátrixot) hogyan lehet létrehozni. Mit ír ki a következő kódrészlet?
vector<vector<int> > d2int(5, vector<int>(10, 3)); for (size_t i = 0; i < 5; i++) { for (size_t j = 0; j < 10; j++) std::cout << d2int[i][j] << " "; std::cout << endl; }
- Készítsünk általános kiíró függvényt a hasonló felépítésű mátrixokhoz! Milyen tárolókkal működik?
- Vektor, lista iterator: hozzunk létre tömbből vektort, majd abból listát iterátorral:
- Csapatokat szeretnénk alkotni. Első körben a csapatnak csak neve van (egyedi) és a csapat tagoknak is csak neve van (csapaton belül egyedi). Szeretnénk mindenféle okos névsorokat gyártani. Ha csak a neveket kell tárolni, akkor ez a fésűs listának kinéző feladat halmazok map-jével megoldható:
std::map<std::string, std::set<std::string> > csapatok;
A csapatnevek egyediségét a map, a csapattagok nevének csapaton belüli egyediségét pedig a set biztosítja. Olvassunk névpárokat a standard inputról (csapat, tag), és tegyük bele a tárolónkba:
Írjuk ki a neveket csapatonként rendezve! Mind a map, mind a set rendezve tárol, ezért csak be kell járnunk a tárolókat és kiírni. A bejáráshoz használhatjuk a for_each algoritmust, ami minden elemre meghív egy függvényt/funktort. Ez egy pair-t fog paraméterként kapni, aminek ez első eleme a csapat neve, a második pedig a csapattagok halmaza. Ezt a halmazt kell bejárnunk a csapattagok nevének kiírásához. Kevésbé igényesen, de kiírás ostream_iterátorral is elvégezhető. - Alakítsunk ki egy olyan fésűs tárolót, amiben Jatekos pointereket tárolunk! A játékos legyen a legegyszerűbb szerkezetű, mivel nem ez most a lényeg:
class Jatekos { std::string nev; int pont; public: Jatekos(std::string n, int p) :nev(n), pont(p) {} int getPont() const { return pont; } std::string getNev() const { return nev; } }; std::ostream& operator<<(std::ostream& os, const Jatekos& j) { os << j.getNev() << " " << j.getPont(); return os; }
A fésű gerincének megvalósításához itt is kézenfekvőnek tűnik a map. Mivel valósítsuk meg a fésű fogait? Miben tároljuk a pointereket?
- set - ettől nem lesznek a játékosnevek egyediek, de az az elemek elérése egyszerű, van find, amivel a beszúrás előtt könnyen tesztelhető a név egyedisége
- list - kézenfekvő megoldás, de nincs find, nincs at/[]
- map - van find, van at/[], de bejárás macerásabb a pair miatt
- vector - nincs find, de van at/[]
- deque - nincs find, de van at/[]
A fentiek alapján adott feladatra talán a set tűnik legalkalmasabbnak a find léte miatt, de rá kell jönnünk, hogy a find nem használható az adott nevű csapattag megkeresésére, mivel azzal egy adott pointert kereshetnénk, nem nevet. Hasonló okokból a csapaton belüli automatikus rendezettséget, mint előnyt is elvesztettük. Így a set alkalmazása már nem tűnik jónak, sőt a rendezésnél nehézségeink is lehetek, ha utólag szeretnénk a halmaz elemeit rendezni. Ezzel szemben a halmaz sablon második paramétereként megadható egy alkalmas összehasonlító függvény, amivel a szükséges rendezettség megtartható. Ennek ellenére a gyakorlás kedvéért a halmaz helyett használjunk mást: válasszuk a list tárolót, és próbáljuk névsorban rendezetten tartani:
- Visszatekintve az előző két feladatra, érdemes a tárolók különbségének okán elgondolkodni. A pointeres esetben set nyújtotta előnyöket egyáltalán nem tudtuk kihasználni. Mi ennek az oka? Az, hogy pointeres esetben a rendezési szempontot nem a tárolt adat adja (ha nem írunk saját hasonlítót a set-hez ill. a map-hez). Ha a pointerek helyett objektumokat tárolnánk, akkor a tároláskor alapértelmezetten használt összehasonlítás (less) művelete az objektum szintjén felüldefiniálható lenne. Nézzük meg így a feladatot: