Programowanie i struktury danych 1 / 30
STL Standard Template Library, STL (ang. = Standardowa Biblioteka Wzorców) biblioteka C++ zawierająca szablony (wzorce), które umożliwiają wielokrotne użycie. Główne składniki STL to kontenery, iteratory i algorytmy. kontener (zasobnik), to struktura danych przechowująca elementy tego samego typu. iterator, umożliwiają obsługę oraz poruszanie się po elementach umieszczonych w kontenerze algorytmy umożliwiają wykonanie określonego zadania np. kopiowanie, zastępowanie, sortowanie itp elementów kontenera 2 / 30
STL Standard Template Library, STL (ang. = Standardowa Biblioteka Wzorców) biblioteka C++ zawierająca szablony (wzorce), które umożliwiają wielokrotne użycie. Główne składniki STL to kontenery, iteratory i algorytmy. kontener (zasobnik), to struktura danych przechowująca elementy tego samego typu. iterator, umożliwiają obsługę oraz poruszanie się po elementach umieszczonych w kontenerze algorytmy umożliwiają wykonanie określonego zadania np. kopiowanie, zastępowanie, sortowanie itp elementów kontenera 3 / 30
Kontenery i iteratory Kontenery (pojemniki) typy generyczne szablony klas służące do przechowywania i udostępniania danych w zorganizowany sposób. Zapewniają narzędzia (dostęp do danych, dodawanie, usuwanie, wyszukiwanie danych w kontenerze, manipulowanie zawartością). Kontenery są homogeniczne tzn. wszystkie elementy kontenera muszą być tego samego typu. Iteratory obiekty pozwalające na dostęp do danych przechowywanych w kontenerze. Nie wymagają znajomości budowy kontenera. 4 / 30
Kontenery Kontenery sekwencyjne - dostęp do poszczególnych składowych możliwy ze względu na pozycję elementu. vector - tablica list - lista deque - lista dwukierunkowa 5 / 30
Kontenery Kontenery asocjacyjne - dostęp do poszczególnych składowych za pomocą klucza. set - zbiór multiset - zbiór z dozwolonymi powtórzeniami. map - (słownik, tablica asocjacyjna) zawiera pary klucz-wartość, elementy dostępne poprzez unikatowy klucz. multimap - mapa z możliwymi kluczami powtarzającymi się. 6 / 30
Kontener vector Kontener vector - inaczej szablon tablicy. Aby wykorzystywać kontener należy dodać plik nagłówkowy # include <vector > Najprostsza deklaracja vector < typename T> nazwa Przykład # include <vector >... vector <int > a ; // pusta tablica vector <float > b(10, 0) ; // 10 elementów zerowych vector <string > s ; // tablica string vector <Osoba > c ; // tablica struktur Osoba Wektor można utworzyć podając pojemność (pojemność = rozmiar) vector <char > v(20) ; oraz można zainicjować wektor określoną wartością vector < float > v( 100,1. 0) ; Obiekt vector można tworzyć, przypisywać jeden obiekt do drugiego, używać operatora [] w celu uzyskania dostępu do elementów wektora. 7 / 30
Kontener vector Kontener vector - inaczej szablon tablicy. Aby wykorzystywać kontener należy dodać plik nagłówkowy # include <vector > Najprostsza deklaracja vector < typename T> nazwa Przykład # include <vector >... vector <int > a ; // pusta tablica vector <float > b(10, 0) ; // 10 elementów zerowych vector <string > s ; // tablica string vector <Osoba > c ; // tablica struktur Osoba Wektor można utworzyć podając pojemność (pojemność = rozmiar) vector <char > v(20) ; oraz można zainicjować wektor określoną wartością vector < float > v( 100,1. 0) ; Obiekt vector można tworzyć, przypisywać jeden obiekt do drugiego, używać operatora [] w celu uzyskania dostępu do elementów wektora. 8 / 30
Wybrane metody kontenera vector size - zwraca liczbę elementów znajdujących się aktualnie w tablicy capacity - pojemność - ilość pamięci aktualnie zarezerwowana na elementy wektora, przed koniecznością realokacji pamięci push_back - dodaje nowy element na końcu tablicy pop_back - usuwa ostatni element tablicy insert - umieszczanie elementu w kontenerze w dokładnie wyznaczonym miejscu resize - ustala nowy rozmiar tablicy Metody kontenera vector 9 / 30
Przykład test36.cpp # include <iostream > # include <vector > # include <iomanip > using namespace std ; int main () { vector <int > tab ; char z ; int liczba ; cout<<" Wpisz 0 na koniec "<<endl ; do { cout<<" Podaj liczbe : " ; cin>>liczba ; tab. push_back ( liczba ) ; } while ( liczba!=0) ; cout<<" Wpisano "<<tab. size ()<<" liczb \ npojemnosc kontenera " <<tab. capacity ()<<endl ; cout<<" Wpisane liczby :\n ------------\n" ; for ( int i=0 ; i<tab. size () ; i++) cout<<setw (5)<<tab [i] ; cout<<endl ; return 0 ; } 10 / 30
Przykład test37.cpp... vector <char> znaki1 (5) ; cout <<" Wpisane znaki ( puste ):\n ------------\n" ; for (int i=0 ; i<znaki1. size () ; i++) cout<<setw (5)<<znaki1 [i] ; cout<<"\ nliczba znakow : "<<znaki1. size () <<"\ npojemnosc kontenera : " <<znaki1. capacity () <<"\n\n *********************************************** "<<endl ; vector <char> znaki2 (5, k ) ; cout<<" Wpisane znaki :\n ------------\n" ; for (int i=0 ; i<znaki2. size () ; i++) cout<<setw (5)<<znaki2 [i] ; cout<<"\ nliczba znakow : "<<znaki2. size () <<"\ npojemnosc kontenera : " <<znaki2. capacity () <<"\n\n *********************************************** "<<endl ; vector <float > v(10) ; cout<<" Wpisane liczby :\n ------------\n" ; for (int i=0 ; i<v. size () ; i++) cout<<setw (5)<<v[i] ; cout<<"\ nwpisano liczb : "<<v. size () <<"\ npojemnosc kontenera : " <<v. capacity () <<"\n\n *********************************************** "<<endl ; } vector < float > a ; cout<<" Pusty kontener :\n ------------\n" ; for (int i=0 ; i<a. size () ; i++) cout<<setw (5)<<a[i] ; cout<<"\ nliczba elementow : "<<a. size () <<"\ npojemnosc kontenera "<<a. capacity ()<<endl ; return 0 ; 11 / 30
Inicjowanie tablicą # include <iostream > # include <vector > # include <iomanip > using namespace std ; test38.cpp int main () { int tab [4] = { 1, 2, 3, 4 } ; // zwykła tablica vector <int > liczby (tab, tab+ sizeof ( tab )/ sizeof ( int ) ) ; cout <<" Rozmiar kontenera : "<< liczby. size () <<"\ npojemnosc kontenera : "<< liczby. capacity ()<< endl ; for ( int i=0 ; i< liczby. size () ; i++) cout << setw (5)<< liczby [i] ; return 0 ; } Kontenery posiadają konstruktor przyjmujący argumenty w postaci iteratorów, które wyznaczają zakres. 12 / 30
Inicjowanie tablicą - cały przykład # include <iostream > # include <vector > # include <iomanip > using namespace std ; test39.cpp int main () { int tab [4] = { 1, 2, 3, 4 } ; // zwykła tablica vector <int > liczby (tab, tab+ sizeof ( tab )/ sizeof ( int ) ) ; cout <<" Rozmiar kontenera : "<< liczby. size () <<"\ npojemnosc kontenera : "<< liczby. capacity ()<< endl ; for ( int i=0 ; i< liczby. size () ; i++) cout << setw (5)<< liczby [i] ; cout << endl << endl ; liczby. push_back (5) ; // dodanie kolejnych elementów liczby. push_back (6) ; // na końcu kontenera liczby. push_back (7) ; liczby. push_back (8) ; cout <<" Rozmiar kontenera : "<< liczby. size () <<"\ npojemnosc kontenera : "<< liczby. capacity ()<< endl ; for ( int i=0 ; i< liczby. size () ; i++) cout << setw (5)<< liczby [i] ; cout<< endl ; return 0 ; } 13 / 30
Macierz Przypomnijmy, że chcą korzystać z wielowymiarowych tablic dynamicznych musimy wykonać szereg operacji int **a = new int *[n] ; for ( int i=0 ; i<n ; i++) a[i] = new int [m] ;... for ( int i=0 ; i<n ; i++) delete [] a[i] ; delete [] a ; Tablice wielowymiarowe można tworzyć również przy użyciu kontenera vector. vector < vector <int > > A ; 14 / 30
Macierz test40.cpp # include <iostream > # include <vector > # include <iomanip > using namespace std ; int main () { vector < vector <int> > A ; int n, m ; cout<<" Rozmiar macierzy A: "<<A. size ()<<"\ npojemnosc macierzy A: " <<A. capacity ()<<endl ; cout<<"podaj liczbe wierszy : " ; cin >>n ; cout<<"podaj liczbe kolumn : " ; cin >>m ; A. resize (n) ; for (int i=0 ; i< A. size () ; i++) A[i]. resize (m) ; cout<<" Rozmiar macierzy A: "<<A. size ()<<"\ npojemnosc macierzy A: " <<A. capacity ()<<endl ; cout<<"rozmiar wiersza macierzy A: "<<A [1]. size ()<<"\npojemnosc wiersza macierzy A: " <<A [1]. capacity ()<<endl ; for ( int i=0 ; i<n ; i++) for ( int j=0 ; j<m ; j++) A[i][j] = i+j+n*m ; for ( int i=0 ; i<n ; i++) { for ( int j=0 ; j<m ; j++) cout<< setw (5)<<A[i][j] ; cout<<endl ; } return 0 ; } 15 / 30
Iterator Iterator jest uogólnieniem wskaźnika, który umożliwia poruszanie się po elementach wektora (kontenera). begin() - wskazuje pierwszy element wektora(kontenera) end() - wskazuje ostatni element wektora(kontenera) Definicja iteratora vector<int >::iterator nazwaiteratora; vector <int > v(10,3) ; vector <int >:: iterator p ; for (p=v. begin () ; p!=v. end () ; p++) cout <<*p<<" " ; // bieżący element kontenera W przypadku innego kontenera, używamy innego iteratora list <int >:: iterator 16 / 30
Iterator - przykład # include <iostream > # include <vector > # include <iomanip > using namespace std ; test41.cpp int main () { vector <int > v( 10,3) ; vector < int >:: iterator p ; for (p=v. begin () ; p!=v. end () ; p++) cout <<*p<<" " ; cout <<"\ nzerujemy kontener \n" ; cout <<" *****************************************\ n" ; for (p=v. begin () ; p!=v. end () ; p++) *p=0 ; cout <<"I ponownie caly \n" ; for (p=v. begin () ; p!=v. end () ; p++) cout <<*p<<" " ; return 0 ; } 17 / 30
Iterator - porównywanie jeżeli p1 i p2 są iteratorami, wtedy porównanie p1 = = p2 zwraca true jeśli p1 i p2 wskazują(lokują) ten sam element, p1!= p2 zwraca true jeśli p1 i p2 nie wskazują(lokują) ten sam element. 18 / 30
Iterator - funkcje begin() i end Funkcja begin( ) ustala pozycję iteratora na pierwszy element kontenera np. v[0]. Zatem iterator p = v. begin ( ) ; Podstawowa pętla jest postaci for (p = v. begin ( ) ; Boolean_Expression ; p++) zadanie dla lokalizacji p ; 19 / 30
Iterator - funkcje begin() i end p = v. end ( ) ; Funkcja end( ) zwraca adres końca kontenera (adres za ostatnim elementem kontenera!). Jeżeli iterator p jest na ostatnim elemencie, wtedy po wykonaniu p++ testowanie p = v.end( ) zwraca wartość true. Zatem prawidłowy warunek zakończenia jest negacją tego warunku. iterator p ; for (p = v. begin ( ) ; p!= v. end ( ) ; p++) zadanie dla lokalizacji p ; vector :: iterator i1 = v. begin () ; vector :: iterator i2 = v. end () ; 20 / 30
Rodzaje iteratorów Główne rodzaje iteratorów do przodu forward iterator dopuszczalne operacje: ++ dwukierunkowe bidirectional iterator dopuszczalne operacje: ++ i - - dostępu swobodnego random-access iterator dopuszczalne operacje: ++, - -, +, +=, -, -=, [] 21 / 30
Przykład Dostęp do elementu kontenera. Drugi i trzeci to przykład iteratora dostępu swobodnego. # include <iostream > # include <vector > using namespace std ; test42.cpp int main ( ) { vector <char > kont ; kont. push_back ( A ) ; kont. push_back ( B ) ; kont. push_back ( C ) ; kont. push_back ( D ) ; for ( int i = 0 ; i < 4 ; i++) cout <<" kontener ["<<i<<"] == "<< kont [i]<< endl ; vector <char >:: iterator p ; p = kont. begin ( ) ; cout <<" Trzecia wartość "<< kont [2] << endl ; cout <<" Trzecia wartość "<<p [2] << endl ; cout <<" Trzecia wartość "<<*(p + 2)<< endl ; 22 / 30
Przykład test43.cpp cout <<" Powracamy na początek do kont [0]. \n" ; p = kont. begin ( ) ; cout <<"i tu mamy wartość "<<*p<< endl ; cout <<" dwa kroki do przodu jeden w tył :\ n" ; p++ ; cout <<*p<< endl ; p++ ; cout <<*p<< endl ; p-- ; cout <<*p<< endl ; kont. push_back ( K ) ; kont. push_back ( R ) ; for (p=kont. begin () ; p!=kont. end () ; p++) cout <<*p<< endl ; return 0 ; } 23 / 30
Przykład p = kont. begin ( ) ; cout <<" Trzecia wartość "<< kont [2] << endl ; cout <<" Trzecia wartość "<<p [2] << endl ; cout <<" Trzecia wartość "<<*(p + 2)<< endl ; oczywiście pierwszy sposób jest wspólny dla kontenerów i tablic. wyrażenia p[2] i *(p + 2) są równoważne, ale nie zawsze mogą być równoważne z pierwszym sposobem. p = kont. begin ( ) ; p++ ; cout <<" Trzecia wartość "<< kont [2] << endl ; // C cout <<" Trzecia wartość "<<p [2] << endl ; // D cout <<" Trzecia wartość "<<*(p + 2)<< endl ; // D 24 / 30
Poruszanie się za pomocą iteratorów 1 w przód - od początku do końca. Początek wyznacza metoda begin(), koniec end(), 2 od końca - od końca do początku. Zakres wyznaczają funkcje od rbegin() do rend(). vector <char >:: reverse_iterator it ; for ( it=kont. rbegin () ; it!=kont. rend () ; ++it ) { cout <<* it<< endl ; } 25 / 30
Uwaga Zapis vector <char >:: iterator p ; for (p=kont. end () ; p!=kont. begin () ; p--) cout <<*p<< endl ; nie powoduje przejrzenia całości kontenera! Zakres jest postaci [begin(),end()) - rozpoczyna się w begin(), kończy w end() ale nie obejmuje end(). Dlatego powyższa pętla ominie A. 26 / 30
Uwaga Zapis vector <char >:: iterator p ; for (p=kont. end () ; p!=kont. begin () ; p--) cout <<*p<< endl ; nie powoduje przejrzenia całości kontenera! Zakres jest postaci [begin(),end()) - rozpoczyna się w begin(), kończy w end() ale nie obejmuje end(). Dlatego powyższa pętla ominie A. 27 / 30
Algorytmy Algorytm sortowania # include <iostream > # include <vector > # include <algorithm > # include <iomanip > # include <ctime > using namespace std ; template < typename T> void wypisz ( vector <T> v) ; int main () { cout <<" wylosowany wektor "<< endl ; vector <int > liczby ; srand ( time ( NULL )) ; for ( int i=0 ; i <10 ; i++) liczby. push_back ( rand () %23 ) ; wypisz ( liczby ) ; cout <<" Bedziemy sortowac \n" ; sort ( liczby. begin (),liczby. end ()) ; wypisz ( liczby ) ; 28 / 30
Algorytmy http://pl.wikibooks.org/wiki/algorytmy w STL 29 / 30
Dziękuję za uwagę!!! 30 / 30