La Standard Template Library Heap, algoritmi e funtori Pericle Perazzo 27 maggio 2011 Algoritmi e strutture dati La Standard Template Library del C++ Riassunto contenitori e iteratori Un contenitore è un oggetto che contiene un insieme di altri oggetti di tipo omogeneo (=gli elementi del contenitore). Un iteratore è un oggetto che punta ad un elemento di un contenitore. 1 Algoritmi e strutture dati La Standard Template Library del C++ Riassunto contenitori e iteratori vector<int> set<int> deque<int> map<string, int> list<int> 2 Algoritmi e strutture dati La Standard Template Library del C++ Riassunto contenitori e iteratori Gli iteratori possono essere usati per visitare o fare operazioni più complesse sui contenitori. list < int > l ; /∗ . . . ∗/ list < int >:: iterator i ; for ( i = l . begin (); i != l . end (); i ++) cout << * i << ’ ’; 3 Algoritmi e strutture dati La Standard Template Library del C++ Riassunto contenitori e iteratori Mobilità degli iteratori: • Forward iterators: possono muoversi in avanti (++) • Bidirectional iterators: possono muoversi avanti e indietro (++, --) – list<>, – set<>, – map<> • Random access iterators: possono fare salti e calcolare distanze (++, --, +=, -=, a-b) – vector<>, – deque<>, 4 Algoritmi e strutture dati La Standard Template Library del C++ Vincoli sulla genericità Un set<T> è un albero binario di ricerca di elementi di tipo T. Posso definire un set<T> per qualsiasi tipo T? No. Il tipo T deve essere ordinabile. Deve essere definito l’operatore < tra due operandi di tipo T (vincolo sulla genericità di T). Per esempio, non può essere definito un set<> di numeri complessi. 5 Algoritmi e strutture dati La Standard Template Library del C++ Heap in C++ 6 Algoritmi e strutture dati La Standard Template Library del C++ priority queue<T> priority queue<T> realizza uno heap di oggetti di tipo T. Vincolo: T deve essere ordinabile (∃ operatore <). #include<queue> Usa la rappresentazione linearizzata e si appoggia ad un vector<T> per la memorizzazione. 7 Algoritmi e strutture dati La Standard Template Library del C++ priority queue<T> • priority_queue::priority_queue() costruttore di default ⇒ O(1) • priority_queue::priority_queue(Iter first, Iter last) costruttore copia dalla sequenza [first, last) e costruisce lo heap ⇒ O(n) • int priority_queue::size() const ⇒ O(1) • bool priority_queue::empty() const ⇒ O(1) • const T& priority_queue::top() const ⇒ O(1) • void priority_queue::push(const T&) ⇒ O(log n) • void priority_queue::pop() elimina l’elemento di cima ⇒ O(log n) • Non ci sono iteratori. che 8 Algoritmi e strutture dati La Standard Template Library del C++ priority queue<T>: esempio int main (){ priority_queue < string > q ; q . push ( " pippo " ); q . push ( " topolino " ); q . push ( " pluto " ); q . push ( " zapotec " ); q . push ( " minnie " ); while (! q . empty ()) { cout << q . top () << " " ; q . pop (); } cout << endl ; } output: zapotec topolino pluto pippo minnie 9 Algoritmi e strutture dati La Standard Template Library del C++ Algoritmi in C++ 10 Algoritmi e strutture dati La Standard Template Library del C++ Algoritmi La Standard Template Library fornisce un insieme di algoritmi più comuni (quicksort, mergesort, ricerca binaria, etc.) #include<algorithm> Ogni algoritmo può essere applicato a molte strutture dati diverse (programmazione generica). 11 Algoritmi e strutture dati La Standard Template Library del C++ Sorting void sort(Iter first, Iter last); Esegue quicksort sugli elementi della sequenza [first, last) (⇒ O(n log n)). Vincoli sulla genericità: • Gli elementi devono essere ordinabili (<). • Gli iteratori devono essere random access (scelta del perno, riconoscimento caso base). – vector<>, – deque<> Ordinamento di un vettore: vector < int > v ; /∗ . . . ∗/ sort ( v . begin () , v . end ()); 12 Algoritmi e strutture dati La Standard Template Library del C++ Sorting Per le liste si usa una speciale funzione membro: list < int > l ; /∗ . . . ∗/ l . sort (); Esegue mergesort su tutta la lista (⇒ O(n log n)). Vincolo: Gli elementi devono essere ordinabili (<). 13 Algoritmi e strutture dati La Standard Template Library del C++ Ricerca lineare Iter find(Iter first, Iter last, const T& val); Esegue una ricerca lineare sulla sequenza [first, last). Restituisce un iteratore al primo elemento trovato uguale a val, o last se l’elemento non esiste. (⇒ O(n)). Vincolo: Gli elementi devono essere confrontabili (∃ operatore ==). vector < int > v ; /∗ . . . ∗/ if ( find ( v . begin () , v . end () , 10) != v . end ()) cout << " Ho trovato un 10! " ; else cout << " Non ho trovato nessun 10. " ; 14 Algoritmi e strutture dati La Standard Template Library del C++ Ricerca binaria bool binary search(Iter first, Iter last, const T& val); Esegue una ricerca binaria sulla sequenza ordinata [first, last). Restituisce true se l’elemento val è stato trovato, false altrimenti (⇒ O(log n)). Vincoli sulla genericità: • Elementi ordinabili (<). • Iteratori random access. vector < int > v ; /∗ . . . ∗/ sort ( v . begin () , v . end ()); if ( binary_search ( v . begin () , v . end () , 10)) cout << " Ho trovato un 10! " ; else cout << " Non ho trovato nessun 10. " ; 15 Algoritmi e strutture dati La Standard Template Library del C++ Ricerca binaria Se voglio ottenere un iteratore che punta all’elemento trovato: Iter lower bound(Iter first, Iter last, const T& val); Esegue una ricerca binaria sulla sequenza ordinata [first, last) (⇒ O(log n)). 1. Se val esiste ed è unico: restituisce un iteratore a val. 2. Se esiste più di un val: restituisce un iteratore al primo val. 3. Se val non esiste: restituisce un iteratore all’elemento immediatamente maggiore (o last se non esiste). 16 Algoritmi e strutture dati La Standard Template Library del C++ Ricerca binaria Ignora tutti gli elementi < val e prende l’estremo inferiore dei rimanenti. val = 10 1. Se 10 esiste ed è unico: 2. Se esiste più di un 10: 3. Se val non esiste: 17 Algoritmi e strutture dati La Standard Template Library del C++ Ricerca binaria Esempio: raddoppio tutti gli elementi che valgono 7: vector < int > v ; /∗ . . . ∗/ sort ( v . begin () , v . end ()); vector < int >:: iterator i ; i = lower_bound ( v . begin () , v . end () , 7); // i 7 p o t r e b b e r o e s s e r e a l l a f i n e , // q u i n d i c o n t r o l l o a n c h e c h e i non v a d a f u o r i while ( i != v . end () && * i == 7) { * i *= 2; i ++; } dal vettore : 18 Algoritmi e strutture dati La Standard Template Library del C++ Algoritmi vari • const T& max(const T& a, const T& b) const T& min(const T& a, const T& b) Restituiscono rispettivamente l’elemento maggiore e minore. Vincolo: definito l’operatore <. • void swap(T& a, T& b) Scambia a con b. Ha complessità costante per i containers (string, vector<>, list<>). • Iter max element(Iter first, Iter last) Iter min element(Iter first, Iter last) Restituiscono rispettivamente l’iteratore all’elemento massimo e all’elemento minimo dell’intervallo [first, last). Vincolo: definito l’operatore <. • Iter copy(Iter first, Iter last, Iter to) Copia gli elementi dall’intervallo sorgente [first, last) all’intervallo destinazione che inizia da to. Restituisce un iteratore alla fine dell’intervallo destinazione. 19 Algoritmi e strutture dati La Standard Template Library del C++ Algoritmi vari vector < int > a ; vector < int > b ; /∗ . . . ∗/ copy ( a . begin () , a . end () , b . begin ()); 20 Algoritmi e strutture dati La Standard Template Library del C++ Funtori 21 Algoritmi e strutture dati La Standard Template Library del C++ Funtori L’invocazione di funzione è un operatore come tutti gli altri (operatore ()). nome f unzione(lista parametri) Posso implementare l’operatore () in una classe: class A { /∗ . . . ∗/ public : int operator () ( int arg1 , int arg2 ){ / ∗ . . . ∗ / } }; La classe A è un funtore (oggetto che rappresenta una funzione) ed è invocabile: int i ; A a; i = a (2 , 3); 22 Algoritmi e strutture dati La Standard Template Library del C++ Funtori void for each(Iter first, Iter last, Funct f) Per ogni elemento nell’intervallo [first, last) esegue f(elemento). Vincolo: f deve essere invocabile con un argomento di tipo T. void stampa ( int a ){ if ( a >= 0 && a <= 5) cout << a << endl ; } int main (){ vector < int > v ; /∗ . . . ∗/ for_each ( v . begin () , v . end () , stampa ); } Se voglio stampare gli interi tra 6 e 10 devo dichiarare una nuova funzione. 23 Algoritmi e strutture dati La Standard Template Library del C++ Funtori Definisco un funtore: class StampaTra { int a , b ; public : StampaTra ( int _a , int _b ){ a = _a ; b = _b ;} void operator () ( int num ){ if ( num >= a && num <= b ) cout << num << endl ; } }; int main (){ StampaTra f (0 , 5); StampaTra f2 (6 , 10); vector < int > v ; /∗ . . . ∗/ for_each ( v . begin () , v . end () , f ); for_each ( v . begin () , v . end () , f2 ); } 24 Algoritmi e strutture dati La Standard Template Library del C++ Funtori • void sort(Iter first, Iter last, Funct less) Ordina [first, last) usando less come funzione di confronto. Vincolo: less deve essere invocabile con il seguente formato: bool less(const T& a, const T& b) • Iter find if(Iter first, Iter last, Funct test) Restituisce un iteratore al primo elemento di [first, last) su cui test ritorna true. Vincolo: test deve essere invocabile con il seguente formato: bool test(const T& a) 25 Algoritmi e strutture dati La Standard Template Library del C++ Funtori Esempio: Ordinare un vettore dal primo elemento che vale tra 1 e 5 in poi. vector < int > v (10); for ( int i = 0; i < 10; i ++) cin >> v [ i ]; Tra f (1 , 5); // f u n t o r e che , i n v o c a t o , r e s t i t u i s c e // t r u e s e i l numero s t a t r a 1 e 5 vector < int >:: iterator j = find_if ( v . begin () , v . end () , f ); sort (j , v . end ()); 26 Algoritmi e strutture dati La Standard Template Library del C++ Funtori I funtori possono essere usati anche per modificare la struttura di alcuni containers. Esempio: set<string> con ordinamento case insensitive (“Pippo” = “pippo”). set<string, NoCaseLess> s; map<string, int, NoCaseLess> m; Vincolo: string). NoCaseLess invocabile con il formato: bool NoCaseLess(string, 27 Algoritmi e strutture dati La Standard Template Library del C++ Esercizio Scrivere un programma che fa le seguenti operazioni: 1. Prende da tastiera 10 interi e li memorizza su un vector<int> (usare un for o il for each). 2. Prende da tastiera un numero N > 0. 3. Ordina il vector con ordinamento modulo N : a <|·|N b ⇔ |a|N < |b|N (usare il sort a 3 argomenti). 4. Stampare su schermo il vettore ottenuto (usare un for o il for each). N =10 28 Algoritmi e strutture dati La Standard Template Library del C++ Esercizio - Soluzione /∗ u t i l i p e r i l f o r e a c h ∗/ void prendi ( int & i ){ cin >> i ;} void stampa ( int i ){ cout << i << ’ ’ ;} / ∗ F u n t o r e che , s e i n v o c a t o , t e s t a s e a è m i n o r e −modulo −N d i b ∗ / class LessModN { int N ; public : LessModN ( int _N ){ N = _N ;} bool operator ()( int a , int b ){ return ( a % N < b % N );} }; 29 Algoritmi e strutture dati La Standard Template Library del C++ int main (){ vector < int > v ; int N ; v . resize (10); // v e t t o r e d i 10 e l e m e n t i a 0 cout << " Vettore : " ; for_each ( v . begin () , v . end () , prendi ); cout << " Modulo di ordinamento : " ; cin >> N ; if ( N <= 0) { cerr << " Errore : N deve essere > 0 " << endl ; exit ( -1); } sort ( v . begin () , v . end () , LessModN ( N )); cout << " Vettore risultante : " ; for_each ( v . begin () , v . end () , stampa ); } 30 Algoritmi e strutture dati La Standard Template Library del C++ Esercizio 2 Scrivere un programma che fa le seguenti operazioni: 1. Prende da tastiera 10 interi e li memorizza su un vector<int> (usare un for o il for each). 2. Ordina i primi 5 elementi (usare il sort). 3. Ordina gli ultimi 5 elementi (usare il sort). 4. Stampa su schermo il vettore ottenuto (usare un for o il for each). 5. Copia gli 8 elementi centrali su una list<int> (usare il copy). 6. Stampa su schermo la lista ottenuta (usare un for o il for each). 31 Algoritmi e strutture dati La Standard Template Library del C++ Esercizio 2 - Soluzione int main ( int argc , char * argv []) { vector < int > v (10); vector < int >:: iterator i ; for ( i = v . begin (); i != v . end (); i ++) cin >> * i ; // p u n t o 1 sort ( v . begin () , v . begin () + 5); // p u n t o 2 sort ( v . begin () + 5 , v . end ()); // p u n t o 3 for ( i = v . begin (); i != v . end (); i ++) cout << * i << ’ ’; // p u n t o 4 cout << endl ; list < int > l (8); copy ( v . begin () + 1 , v . end () - 1 , l . begin ()); // p u n t o 5 list < int >:: iterator j ; for ( j = l . begin (); j != l . end (); j ++) cout << * j << ’ ’; // p u n t o 6 cout << endl ; } 32 Algoritmi e strutture dati La Standard Template Library del C++ Esercizio 2 - Soluzione con for each void prendi ( int & num ){ cin >> num ;} void stampa ( int num ){ cout << num << ’ ’ ;} int main ( int argc , char * argv []) { vector < int > v (10); for_each ( v . begin () , v . end () , prendi ); // p u n t o 1 sort ( v . begin () , v . begin () + 5); // p u n t o 2 sort ( v . begin () + 5 , v . end ()); // p u n t o 3 for_each ( v . begin () , v . end () , stampa ); // p u n t o 4 cout << endl ; list < int > l (8); copy ( v . begin () + 1 , v . end () - 1 , l . begin ()); // p u n t o 5 for_each ( l . begin () , l . end () , stampa ); // p u n t o 6 cout << endl ; } 33