Előadást letölteni
Az előadás letöltése folymat van. Kérjük, várjon
1
C++ Standard Template Library
Dudás László Miskolci Egyetem Alkalmazott Informatikai Tanszék
2
STL – Standard Template Library
A. Stepanov és M. Lee találmánya Mottó: Don’t reinvent the wheel; use libraries, Bjarne Stroustrup: The C++ Programming Language, 2000 Generikus Tárolók Generikus Algoritmusok Generikus Bejárók 1
3
STL A generalitást, általánosságot a templétek nyújtják
általános osztály = class templét általános algoritmus = function templét Mi a templét? (Roberto E. Lopez-Herrejon) Keret az általános programozáshoz A típusok a templétek paraméterei Paramétereken keresztül megjelenő polimorfizmus Cél: gyors fejlesztés és kiváló bővíthetőség STL OOP 2
4
STL Példa template <class T> T minab(T a, T b) { T min; if (a < b) min = a; else min = b; return min; } int c = 2, d = 5, min; float f = 3.3, g = 2.2, min; min = minab(c,d); min = minab(f,g); cout << ”min=” << min; cout << ”min=” << min; 3
5
1.source: www.politikimfreientheater.de
Tárolók Asszociatív set multiset map multimap Szekvenciális vector list deque 1. Adaptált que priority que stack 4 1.source:
6
1.source: www.politikimfreientheater.de
Tárolók Asszociatív set: kulcsok halmaza, a kulcs egyértelmű és rendezett multiset: kulcsok halmaza, duplikált kulcs megengedett. map: egyedi kulcs – egyedi adatelem párok. multimap: egyedi kulcsok halmazának és adatelemeknek az egymáshozkapcsolása, egy kulcshoz több adatelem kapcsolódhat. Szekvenciális vector: hosszát növelni képes vektor. list: rendezett elemek, bármely pozícióba új elem szúrható be, vagy törölhető. deque: olyen vektor, mely elejére és végére illeszthetünk újabb elemet, vagy onnan törölhetünk. Adaptált que: FIFO sor priority que: a prioritásértékkel rendelkező elem a prioritásának megfelelő helyre kerül, rendezett sor stack: LIFO sor, verem 1. 5 1.source:
7
1.source: www.politikimfreientheater.de
Tárolók Szekvenciális tárolók (vector, list, deque) jellemzői Az elemek szekvenciális elhelyezkedésűek Az elemek pozíciója rögzített A pozíció a beszúrás helye és ideje által meghatározott A pozíció nem függ az elem értékétől Az elemek rendszerint nem rendezettek értékük szerint. 1. 6 1.source:
8
A vector tároló #include <vector> A vector tároló a std scope-hoz, névtérhez tartozik és a <vector> header file deklarálja. Jellemzői A C vektor típus általánosítása Az elemek írásra/olvasásra való véletlen elérése [ ] index útján O(1) időben A mérete hatékonyan változtatható elem végéhez adásával, ill. onnan való törlésével, O(1) időben Nem hatékony elembeszúrás/törlés a vektor közepén, O(n) időben Az újraméretezés O(n) időt igényel Az elemek tetszőleges T típusúak lehetnek, de a következő tagfüggvényeket definiálni kell: copy konstruktorok T(t) és T(const_t), destruktor ~T( ), címe t &t, értékadás: t= operátor. Default tárolóként szolgál a priority_queue tárolóhoz Hasonlóan más tárolókhoz, a vector tárolónak is van begin() és end() tagfüggvénye a bejárónak az első és utolsó elemre való beállításához. 1. 7 1. source:
9
vector < int > v(14);
Deklarálás, konstruktorok és destruktor Konstruktorok: A vektor inicializálható a méretének, továbbá kezdőértékének megadásával, akár másik vektor útján is: vector<T> v; // üres vektor vector<T> v(n); // n elemű vektor, igényli a default T // konstruktor megadását vector<T> v(n, T init); // n elemű vektor T kezdőértékekkel // feltöltve vector<T> v(w); // v vektor inicializálása a w vektorral vector<T> v(iterator1, iterator2); // elemek átmásolása // másik tárolóból Destruktor: ~vector(); // törli a vektor elemeit és a vektort magát 3 1 7 2 5 4 vector < int > v(14); v[6]=2; e= v[2]; v.push_back(3); v.pop_back(); v.begin() v.end() 9 8
10
Tagfüggvények Tulajdonságok, méretmódosítás
v.begin() Az első elemre mutató bejáróértéket ad vissza v.end() A végére, az első üres elemre mutató bejáróértéket ad vissza v.rbegin() Veszi a fordított vektort és az első elemre mutató bejáró értékét adja vissza v.rend() Veszi a fordított vektort és az utolsó elemre mutató bejáró értékét adja vissza == Két vektor egyezését vizsgálja != Két vektor eltérését vizsgálja < Két vektor lexikografikus összehasonlítása v.empty() Igaz, ha a vektor üres, egyébként hamis v.size() A vektor elemszámát adja ( <= v.capacity() ) v.max_size() A legnagyobb lehetséges vektorméret v.capacity() Lefoglalt terület mérete ( >= elemek által használt terület, elemekben mérve) v.reserve(n) Előzetes memóriafoglalás n elem részére a gyakori push_back()hívások miatti átméretezések megelőz. v.resize(n, T init=T() ) Átméretezi a tárolót n db T típusú elem hozzáadásával, igényelheti a tartalom átmásolását. 9
11
Tagfüggvények .. Értékadás elemnek, elem lekérdezése és törlése
v.push_back(e) Egy elemet a végéhez fűz, a méretet módosítja v.insert(p,e) Beszúrja az e elemet a p pozíciónál v1 = v2; Értékadás az elemek átmásolásával v.assign(n,e) A v feltöltése n db e elemmel v.assign(it1, it2) Elemek átvétele az [it1, it2] intervallumból [ ] Indexes elérés tartományellenőrzés nélkül, referenciát ad vissza az elemre v.at(n) Indexes elérés tartományellenőrzéssel, referenciát ad vissza az elemre v.front Az első elemre vonatkozó referenciát ad v.back() Az utolsó elemre vonatkozó referenciát ad v.pop_back() Törli az utolsó elemet, méretet aktualizálja v.erase(p) Törli a p pozícióban lévő elemet v.clear() Eltávolítja az összes elemet. 9 10
12
Példa a tagfüggvények alkalmazására
#include <iostream> #include <vector> using namespace std; void main(){ vector<int> v; cout << v.size()<<endl; // 0 v.reserve(10); v[0]= v[1]= v[2]= 8; for (int i=0; i<v.size(); i++)// [] nem módosította a méretet!! cout << v[i] << " "; // Nem ír ki egyetlen értéket sem !! v.push_back(5); v.push_back(10); v.push_back(15); for (int i=0; i<v.size(); i++) cout << v[i] << " "; // v.pop_back(); cout << v[i] << " "; // 5 10 cout << v.size()<<endl; // 2 cout << v.at(1)<<endl; // 10 cout << v.at(3); // ERROR! } 11
13
Bejárók a vektorokhoz #include <vector>
A vektorok és az algoritmusok bejárókon keresztül kommunikálnak Mindegyik tárolótípus saját bejárótípust használ az elemek bejárásához A változó bejáró lehetővé teszi az elem megváltoztatását: vector<int> :: iterator pos; A konstans bejáró nem engedi a mutatott érték módosítását: vector<char> :: const_iterator it; Példa: 7 2 5 4 v.begin() v.end() 9 iterator Vectorok Algoritmusok Bejárók #include <iostream> #include <vector> using namespace std; void main(){ vector<int> v(5, 25); // Inicializálás vector<int>::const_iterator it; for ( it = v.begin(); it != v.end(); ++it ) cout<< *it << " "; // } 12
14
Fordított bejárók A fordított bejárók ( reverse_iterator, const_reverse_iterator ) megfordítják az inkrementálás és a dekrementálás működését. Az algoritmusokban fordított bejárót használva a megadott intervallum elemei fordított sorrendben kerülnek feldolgozásra : 7 2 5 4 v.begin() v.end() 9 iterator #include <iostream> #include <vector> using namespace std; void square( int& element){ element *= element; cout << " " << element; } int main() { vector<int> v; for (int i = 0; i < 5; i++) v.push_back( i ); //A vektor dinamikus felépítése vector<int>::reverse_iterator rit; for (rit = v.rbegin() ; rit!=v.rend(); ++rit) square(*rit); // return 0; 1 2 3 4 16 9 v v.rbegin() v.rend() rit 13
15
Bejáró műveletek A bejárók pointer-szerűen működnek, a mutatók általánosításai. Az általánosítás azt jelenti, hogy általános algoritmusokat írhatunk, melyek bármely tároló típuson működni fognak Egy vektorhoz akárhány bejárót rendelhetünk Egy intervallum megadása két bejárót igényel Egy vektorbejáró egy Random Access kategóriájú bejáró amely összes képességét a Bi-directional és a Forward bejáró kategóriáktól örökli Vektor típus esetén mind használható. Az ++i jobb, mint az i++ mert az egy ideiglenes objektum létrehozása és visszaadása után inkrementál. 7 2 5 4 v.begin() v.end() 9 iterator Random Access iterator it[ n ] it+= n it-= n it+n n+it it-n it1-it2 it1<it2 it1>it2 it1<=it2 it1>=it2 Bi-directional iterator --it it-- Forward iterator *it it->memb ++it it++ it1==it2 it1!=it2 it1=it2 14
16
Bejáró műveletek példa
Az it[] használata vektorelemek random elérésére 7 2 5 4 v.begin() v.end() 9 iterator #include <iostream> #include <vector> using namespace std; void main() { vector<float> v(5, 12.5); vector<float>:: iterator iv= v.begin(); vector<float> w(iv+2, v.end()); vector<float>:: iterator iw; iw= w.begin(); int i= 0; while ( iw < w.end() ) { iv[i] += *iw; // iv[i] , not v[i] !! ++i; ++iw; } for (i=0; i<5; ++i) cout << iv[i] << " "; // 15
17
Bejáró példák Hasonlóság van a C vektorok mutatói és a bejárók között:
7 2 5 4 v.begin() v.end() 9 iterator … // C mutató példa (részlet) int v[ ] = { 3, 5, 7, 4, 2}; int n = sizeof(v) / sizeof(int); for ( int* p= v; p != v+n; p++) cout << *p << ” , ”; … … // Bejáró példa int vv[ ] = { 3, 5, 7, 4, 2}; vector<int> v(vv, vv+5); for (vector<int> :: iterator pos; pos != v.end(); ++pos) cout << *pos << ” , ”; 16
18
Bejáró példák .. Bejárók, mint függvény paraméterek 17
2 5 4 v.begin() v.end() 9 iterator #include <iostream> #include <vector> using namespace std; int odds(vector<int>::iterator begin, vector<int>::iterator end) { int count= 0; for ( ; begin != end; ++begin) if (*begin % 2 == 1) count++; return count; } void main() { int vv[]={1,2,3,4,5}; vector<int> v(vv,vv+5); cout << odds(v.begin(), v.end()) << " "; // 3 17
19
Generikus algoritmusok #include <algorithm>
A tárolókon működő ezen algoritmusok hatékonyan valósítanak meg olyan gyakran használt műveleteket, mint a min,max,sort,find. A templétekkel deklarált algoritmusok gyakorlatilag függetlenek a tároló és a tárolóelemek típusától Az algoritmusok a tárolókat bejárókon keresztül kezelik A 60 fő algoritmus lefedi a tárolók által igényelt összes működést Ezen algoritmusok rugalmassága a programozó által definiálható függvények, mint paraméterek és a szabadon választható beépített logikai függvények (más néven predikátumok, függvény objektumok) következménye. 1. vector Algoritmus bejárók list set 18 1. Source: serp.la.asu.edu/.../ travel1_imag/gears.gif
20
! A generikus algoritmusok jellemzői
Az algoritmusok a hatékonyságot a biztonság elé helyezik A gyors működés elérése miatt nem végeznek tartományhatár ellenőrzést Egy, vagy több intervallumon működnek Az első intervallum két bejáró által meghatározott, a második egy, az első elemre mutató által A felülíró mód beszúróra váltható beszúró bejárók alkalmazásával Legyünk óvatosak Az intervallumoknak érvényeseknek kell lenniük A célintervallumok legyenek elegendően hosszúak. ! 19
21
A fő generikus algoritmusok
Nem módosító algoritmusok for_each() Megadott műveletet hajt végre a vektor minden elemére (lehet módosító is) find() A megadott elem első előfordulására mutató bejárót ad vissza find_if() A megadott feltételnek, logikai függvénynek eleget tevő első elemre mutató bejárót ad vissza find_first_of() Az első előfordulását adja egy sorozat olyan értékének, amely előfordul a másik sorozatban is adjacent_find() Szomszédos értékpár első előfordulását adja max_element() Az intervallum legnagyobb elemére mutató bejárót ad vissza min_element() Az intervallum legkisebb elemére mutató bejárót ad vissza count() Egy megadott érték egy intervallumban való előfordulásainak számát adja count_if() Egy logikai függvényt kielégítő elemek számát adja egy intervallumban accumulate() Az intervallum elemeinek összegét adja equal() Két tartományt összehasonlít. 20
22
A fő generikus algoritmusok ..
Módosító algoritmusok transform() Egy műveletet alkalmaz minden elemre. Az eredmény tárolódhat egy másik vektorban, vagy ugyanabban. copy() Másol egy sorozatot replace() Adott értékű elemeket egy másik adott értékre cserél replace_if() Egy logikai feltételt kielégítő elemeket megadott értékre cserél remove() Adott értékkel egyező elemeket eltávolítja remove_if() Adott feltételt kielégítő elemeket eltávolítja reverse() Megfordítja a vektor tartalmát random_shuffle() Egyenletes eloszlású véletlen permutációját adja az elemeknek fill() Feltölti a vektort egy megadott értékkel generate() Adott függvény által generált elemekkel tölti fel a vektort Rendező algoritmusok sort() Rendezi az elemeket stable_sort() Az egyező elemek sorrendjét megtartva rendez binary_search() Bináris keresést végez rendezett sorozatban. 21
23
Példa az algoritmusok használatára
Függvénymutató paraméter alkalmazása #include <iostream> #include <vector> #include <algorithm> using namespace std; int cube(int e) {return e*e*e;} bool predicate_greater(int e){return e > 100;} void main(){ int vec[]={3,6,7,4,2}; vector<int> v(vec, vec+5); transform( v.begin(), v.end(),v.begin(), cube ); for (int i=0; i<5 ; i++) cout<<v[i]<<" "; // remove_if( v.begin(), v.end(), predicate_greater ); // cout<< endl<< v.size() <<endl; // 5, size is not modified!! v.pop_back(); v.pop_back(); // size == 3 for (int i=0; i<v.size() ; i++) cout<<v[i]<<" "; // sort( v.begin(), v.end() ); cout<<endl; for (int i=0; i<v.size() ; i++) cout<<v[i]<<" "; // } 22
24
Függvényobjektumok #include <functional>
Az objektum nevéhez csatolt függvényargumentum obj(arg) egy függvényként használható szintaxist ad, amelynek működéseként az osztályban definiált operator() (arg) {működés} függvény fut le. A függvényobjektumot argumentumként át lehet adni a generikus algoritmusnak, hogy módosítsuk annak alapértelmezett működését a szükségleteinknek megfelelően. Tulajdonképpen a függvénypointereknek az objektum általánosításai az operator() átdefiniálásával az osztályban. Előredefiniált függvényobjektumok léteznek különféle predikátumok (logikai függvények) megvalósítására a <functional> header-ben, pl.: equal_to(), not_equal_to(), greater(), less(), greater_equal(), less_equal(), logical_and(), logical_or(), logical_not() relációs és logikai operátorok helyettesítésére. Írhatunk predikátum és nem predikátum függvényeket is saját szükségleteink szerint. 23 1. Source:
25
Függvényobjektum (Function object) példa
#include <iostream> // Példa: Egy rugalmasabb, paraméterezhető #include <vector> // vektorelemszűrő függvényobjektum definiálása #include <algorithm> // A for_each() fv miatt using namespace std; class fv_obj_NagyobbakKiirasa { // A függvényobjektum osztálya int alsohatar; public: fv_obj_NagyobbakKiirasa(int hatar) { alsohatar = hatar; } void operator() (int elem) { // Az elemet a hívó vektorból vesszük if (elem > alsohatar) cout << endl << elem; } }; void main(){ int vec[]={3,6,7,4,2}; vector<int> v(vec, vec+5); for (int i=0; i<5 ; i++) cout<< v[i] <<" "; // fv_obj_NagyobbakKiirasa fvo(3); // Az fvo függvényobjektum // létrehozása for_each(v.begin(),v.end(),fvo); // A for_each() belső it // iterátorával elért fvo(*it) vektorelemmel hívja meg a // függvényobjektum operator() függvényét sorra minden elemre // 6 7 4 } 24 1.
26
Megjegyzések Használjunk typedef-et a hosszú vektor típus nevek elkerülésére: Legyünk óvatosak az érvénytelen vektorelemekkel: Érvénytelen hivatkozás elkerülésére használjuk: A konstruktort memóriafoglalásra push_back() a méret kiterjesztésére reserve() elegendő memória előfoglalására size() elérés előtti ellenőrzésre. Legyünk óvatosak az átméretezéssel resize() érvényteleníti a vektorelemekre mutató pointereket mert módosítja az elemek helyét. (new, másolás, delete által) // typedef nélkül : vector<vector <OwnType > > matrix; vector<vector <OwnType > > :: iterator it; // typedef használatával : typedef vector<vector <OwnType > > Tmatrix; Tmatrix matrix; Tmatrix :: iterator it; vector<int> v; v[10] = 5; // Hibás! 25 1.
Hasonló előadás
© 2024 SlidePlayer.hu Inc.
All rights reserved.