Standard Template Library STL Claudio Esperana Paulo Roma
Standard Template Library STL Claudio Esperança Paulo Roma Cavalcanti 2008 LCG/UFRJ. All rights reserved. 1
O que é a STL? • STL é uma biblioteca padrão com as estruturas de dados mais usadas em Computação. ▪ Foi criada para evitar a implementação e teste das mesmas estruturas de dados eternamente. ▪ Por isso, economiza muito tempo e evita “dor de cabeça” desnecessária. • Por que templates? ▪ Elas lhe poupam da tarefa de reimplementar o código para cada novo tipo de dado da sua aplicação. 2008 LCG/UFRJ. All rights reserved. 2
STL • Quando usadas apropriadamente, as templates são bastante eficazes. ▪ No entanto, as mensagens de erro costumam ser pouco elucidativas. • Uma boa fonte sobre a STL é o guia de programação da SGI. ▪ Ou então a nossa implementação de um subconjunto da STL. • Na nossa implementação, cada classe tem o prefixo “utl” (não havia namespace ainda). ▪ Se a variável de compilação USE_STL estiver definida, o prefixo será suprimido, “cgc. Util: : ” será substituído por “std: : ”, e o compilador usará a STL nativa então. 2008 LCG/UFRJ. All rights reserved. 3
Estrutura da STL • A STL oferece: ▪ Containers (recipientes). ▪ Iterators (iteradores). ▪ Algorithms (algoritmos). • Recipientes servem para armazenar dados e podem ser classificados como: ▪ Seqüências de dados ▪ Recipientes associativos para pares de objetos (chave, dado). ▪ Adaptadores que provêem um subconjunto da funcionalidade de um recipiente. ◦ Pilhas, filas de prioridade. 2008 LCG/UFRJ. All rights reserved. 4
Iteradores • Iteradores foram criados para permitir uma maneira unificada de percorrer ou recuperar dados de recipientes. ▪ Escondem os detalhes de implementação, principalmente ponteiros, das aplicações. ▪ Portanto, geralmente é possível trocar o tipo de recipiente e ainda assim usar o mesmo código. • A STL adota a filosofia de manter os algoritmos fora das classes dos recipientes. ▪ A razão é permitir que o mesmo algoritmo possa agir sobre recipientes diferentes. 2008 LCG/UFRJ. All rights reserved. 5
Exemplo • Geralmente os algoritmos são implementados usando iteradores apenas. ▪ Ordenação, busca, contagem, substituição, etc. . . ▪ Iteradores tem operadores de incremento “++” definidos. ▪ Ponteiros podem ser usados como iteradores. 2008 LCG/UFRJ. All rights reserved. 6
#include <vector> #include <iostream> using namespace std; /** função objeto. * Insere T em um stream de saída. * Substitui “passar ponteiro para função” de C. */ template <class T> struct print : public unary_function <T, void> { print(ostream& out) : os(out), count(0) {} void operator() (T x) { os << x << ' '; ++count; } ostream& os; int count; }; Construtor int { 7 Redefine operador ( ) Calcula o Chama print() tamanho de para cada main() A Guarda elemento de A Dois int A[] = {1, 4, 2, 8, 5, 7}; número de const int N = sizeof(A) / sizeof(int); iteradores elementos print<int> P = for_each(A, A + N, print<int>(cout)); impressos cout << endl << P. count << " objects printed. " << endl; Imprimindo elementos de um vetor return 1; } 1 4 2 8 5 7 6 objects printed. 2008 LCG/UFRJ. All rights reserved.
Vector • vector é o recipiente mais simples da STL. ▪ É uma seqüência que suporta acesso aleatório aos seus elementos. ▪ Inserção e remoção de elementos no final em O(1). ▪ Inserção e remoção de elementos no meio em O(n). ▪ Busca em O(n). ▪ Gerenciamento automático de memória. ▪ Iteradores estão invalidados após realocação de memória, inserção e remoção no meio. ▪ Descrição e implementação. 2008 LCG/UFRJ. All rights reserved. 8
#include <vector> #include <iostream> #include <iterator> #include <ext/algorithm> using namespace std; using __gnu_cxx: : is_sorted; 9 Insere no final de V. int main() { vector<int> V; Insere V no V. push_back(20); Ordena V V. push_back(30); stream de V. push_back(-1); com merge saída V. push_back(-1); sort. V. push_back(-1); Verifica se cout << "V: n"; copy(V. begin(), V. end(), ostream_iterator<int>(cout, " ")); V está stable_sort (V. begin(), V. end()); ordenado. cout << "n. V: sortedn"; copy(V. begin(), V. end(), ostream_iterator<int>(cout, " ")); cout << "n. V: is sorted? "; cout << is_sorted ( V. begin(), V. end() ) << "n"; Uso da classe vector. } V: 20 V: -1 V: 30 -1 -1 -1 sorted -1 -1 20 30 is sorted? 1 2008 LCG/UFRJ. All rights reserved.
/** copies elements from a container to another. * * Copies elements from the range [first, last) to the * range [result, result + (last - first)). * That is, it performs the assignments * *result = *first, *(result + 1) = *(first + 1), and so on. * Generally, for every integer n from 0 to last - first, * copy() performs the assignment *(result + n) = *(first + n). * Assignments are performed in forward order, i. e. in order of * increasing n. * * The return value is result + (last - first) * * @param first where to start copying. * @param last where to end copying. * @param result where to copy. * @return result + (last-first). */ template<class Input. Iterator, class Output. Iterator> inline Output. Iterator copy(Input. Iterator first, Input. Iterator last, Output. Iterator result) { for( Input. Iterator itr = first; itr != last; ++itr, ++result ) { *result = *itr; } return result; } Apenas percorre o recipiente de entrada. Derivados da mesma classe base. 10 Função copy. E atribui ao recipiente da saída. 2008 LCG/UFRJ. All rights reserved.
Deque • deque (Double Ended Queue) é como um vetor com inserção eficiente na frente também. ▪ É uma seqüência que suporta acesso aleatório aos seus elementos. ▪ Inserção e remoção de elementos no meio em O(n). ▪ Busca em O(n). ▪ Inserção e remoção de elementos na frente e no final em O(1). ▪ Gerenciamento automático de memória. ▪ Iteradores estão invalidados após realocação de memória, inserção e remoção no meio. ▪ Descrição e implementação. 2008 LCG/UFRJ. All rights reserved. 11
#include <deque> #include <iostream> #include <iterator> 12 using namespace std; int main() { deque<int> Q; Q. push_back(3); Insere 5 três Q. push_front(1); Q. insert(Q. begin() + 1, 2); vezes após a Q[2] = 0; primeira copy(Q. begin(), Q. end(), ostream_iterator<int>(cout, " ")); posição. cout << "n"; // The values that are printed are 1 2 0 Q. insert(Q. begin() + 1, (size_t)3, 5); Q. push_front(7); Q. push_front(8); Q. push_front(9); Uso da classe deque. 2008 LCG/UFRJ. All rights reserved.
Redimensiona P copy(Q. begin(), Q. end(), completando cout << "n"; com. P 88 no final. deque<int> = Q; 13 ostream_iterator<int>(cout, " ")); copy(Q. begin(), Q. end(), ostream_iterator<int>(cout, " ")); Remove os dois cout << "n"; primeiros P. resize ( 18, 88 ); elementos de P. P. push_front ( 99 ); P. push_front ( 98 ); copy(P. begin(), P. end(), ostream_iterator<int>(cout, " ")); P. erase ( P. begin(), P. begin()+2 ); Último cout << "n"; elemento de P cout << P. back(); cout << "n"; Primeiro cout << P. front(); elemento de P cout << "n"; cout << *P. begin(); cout << "n"; } 1 2 0 9 8 7 1 5 5 5 2 0 98 99 9 8 7 1 5 5 5 2 0 88 88 88 9 9 Uso da classe deque. 2008 LCG/UFRJ. All rights reserved.
List • list é de fato uma lista duplamente encadeada. ▪ É uma seqüência que suporta percurso para frente e para trás. ▪ Busca em O(n). ▪ Inserção e remoção de elementos na frente, no meio e no final em O(1). ▪ Iteradores ainda estão válidos após inserção, splicing ou remoção. ▪ Descrição, Implementação. 2008 LCG/UFRJ. All rights reserved. 14
#include <list> #include <iostream> #include <iterator> 15 using namespace std; Insere 0 no final de LInsere 1 no int main() { início de L. list<int> L; L. push_back(0); L. push_front(1); L. insert(++L. begin(), 2); copy(L. begin(), L. end(), ostream_iterator<int>(cout, " ")); cout << "n"; list<int> M ( L ); Insere 2 L. splice ( ++++L. begin(), M ); após a copy(L. begin(), L. end(), ostream_iterator<int>(cout, " ")); cout << “n”; primeira copy(M. begin(), M. end(), ostream_iterator<int>(cout, " ")); } Move elementos de M para L. 1 2 0 0 Uso da classe list. posição. M está vazia. 2008 LCG/UFRJ. All rights reserved.
String • string toma o lugar de um “array of char”. ▪ Não é mais necessário se preocupar com o tamanho do arranjo. ▪ Oferece todas as funções de C pertinentes a strings como membros da classe. ▪ Evita erros relacionados com ponteiros, na chamada de funções que recebem ou retornam strings. ▪ Descrição, Implementação. 2008 LCG/UFRJ. All rights reserved. 16
#include <string> #include <iostream> using namespace std; int main () { //test constructors string str 0; cout << "empty constructor: " << str 0 << endl; cout << "str 0 size = " << str 0. size() << endl; mesmo que world!"); string O str 1("hellow Comprimento Capacidade da // 0123456789012 length. Tamanho cout << atual "constructor: string da char string sem termáximo" << str 1 << endl; cout << "data de = " << str 1. data() que uma string << endl; realocar. cout << "size = " << pode str 1. size() << endl; ter. cout << "length = " << str 1. length() << endl; cout << "capacity = " << str 1. capacity() << endl; cout << "max_size = " << str 1. max_size() << endl; // empty cout << "str 0 empty = " << str 0. empty() << endl; cout << "str 1 empty = " << str 1. empty() << endl; empty constructor: str 0 size = 0 const char constructor: hellow world! data = hellow world! size = 13 length = 13 capacity = 13 max_size = 13 str 0 empty = 1 str 1 empty = 0 17 Uso da classe string. 2008 LCG/UFRJ. All rights reserved.
string str 2(str 1); cout << “copy constructor: " << str 2 << endl; string str 3(str 1, 4, 6); cout << "string&, pos, npos, str 3 constructor: " << str 3 << endl; string str 4("hellow word!", 6); Troca o npos, str 4 constructor: " << str 4 << endl; cout << "char[], string str 5(12, conteúdo 'h'); de cout << “n, char str 5 constructor: " << str 5 << endl; str 5 por str 1. cout << "str 5 size = " << str 5. size() << endl; // swap str 5. swap(str 1); cout << "swap str 1 and str 5" << endl; cout << "str 1 = " << str 1 << endl; cout << "str 5 = " << str 5 << endl; 18 Uso da classe string. } copy constructor: hellow world! string&, pos, npos, str 3 constructor: ow wor char[], npos, str 4 constructor: hellow n, char str 5 constructor: hhhhhh str 5 size = 12 swap str 1 and str 5 str 1 = hhhhhh str 5 = hellow world! 2008 LCG/UFRJ. All rights reserved.
Set • set é uma coleção ordenada de objetos do tipo “key” sem duplicatas. ▪ Operações de conjunto como interseção, união e diferença são eficientes. ▪ Implementado por uma árvore balanceada de busca (Red Black, Splay). ▪ Busca em O(log n). ▪ Descrição, Implementação. • multiset é a versão que permite duplicatas. ▪ Descrição, Implementação. 2008 LCG/UFRJ. All rights reserved. 19
#include <set> #include <iostream> using namespace std; 20 Retorna se s 1 é lexicograficamente /// função objeto. Compara duas struct ltstr menor que s 2 { seqüências de caracteres. bool operator()(const char* s 1, const char* s 2) const { return strcmp(s 1, s 2) < 0; } }; int main() { const int N = 6; const char* a[N] = {"isomer", "ephemeral", "prosaic", "nugatory", "artichoke", "serif"}; const char* b[N] = {"flat", "this", "artichoke", "frigate", "prosaic", "isomer"}; Construtor a partir de dois iteradores Uso da classe set<const char*, ltstr> A(a, a + N); set<const char*, ltstr> B(b, b + N); set<const char*, ltstr> C; 2008 LCG/UFRJ. All rights reserved.
cout << "Set A: copy(A. begin(), cout << endl; cout << "Set B: copy(B. begin(), cout << endl; A ∪ B. "; A. end(), ostream_iterator <const char*>(cout, " ")); 21 "; B. end(), ostream_iterator <const char*>(cout, " ")); cout << "Union: "; set_union(A. begin(), A. end(), B. begin(), B. end(), ostream_iterator<const char*>(cout, " "), ltstr()); cout << endl; A ∩ B. cout << "Intersection: "; set_intersection(A. begin(), A. end(), B. begin(), B. end(), ostream_iterator<const char*>(cout, " "), ltstr()); cout << endl; A – B. set_difference(A. begin(), A. end(), B. begin(), B. end(), inserter(C, C. begin()), ltstr()); cout << "Set C (difference of A and B): "; copy(C. begin(), C. end(), ostream_iterator <const char*>(cout, " ")); cout << endl; } Uso da classe set. Insere o resultado em C. Set A: artichoke ephemeral isomer nugatory prosaic serif Set B: artichoke flat frigate isomer prosaic this Union: artichoke ephemeral flat frigate isomer nugatory prosaic serif this Intersection: artichoke isomer prosaic Set C (difference of A and B): ephemeral nugatory serif 2008 LCG/UFRJ. All rights reserved.
Map • map associa objetos do tipo “key” a objetos do tipo “data”. ▪ Nenhum par de elementos possui a mesma chave. ▪ Percurso é ordenado. ▪ Indicada para implementação de dicionários. ▪ Implementada por uma árvore balanceada de busca (Red Black, Splay). ▪ Busca em O(log n). ▪ Descrição, Implementação. • multimap é a versão que permite duplicatas. ▪ Descrição, Implementação. 2008 LCG/UFRJ. All rights reserved. 22
#include <map> #include <string> #include <iostream> 23 Chave e dado. using namespace std; Duas formas de inserção typedef map < long, string > map. Type; typedef map. Type: : value_type Value. Pair; int main() { map. Type Map; Map[836361136] = "Andrew"; Map[274635328] = "Berni"; Map[974635328] = "Ulisses"; Map[277735328] = "Paulo"; Map[277825328] = "Pedro"; Map[266735328] = "Peter"; Map[275734328] = "Paula"; Map[275839328] = "Paulos"; Map. insert(Value. Pair(260736622, "John")); Map. insert(Value. Pair( 720002287, "Karen")); Map. insert(Value. Pair(138373498, "Thomas")); Map. insert(Value. Pair(135353630, "William")); // insertion of Xaviera is not executed, because // the key already exists. Map. insert(Value. Pair( 720002287, "Xaviera")); Cria um par (chave, dado). Uso da classe map. Type Map 2 ( Map. begin(), Map. end() ); cout << "equality operator " << (Map 2 == Map) << endl; equality operator 1 Output: 974635328: Ulisses 836361136: Andrew 720002287: Karen 277825328: Pedro 277735328: Paulo 275839328: Paulos 275734328: Paula Ordem decrescente. 2008 LCG/UFRJ. All rights reserved.
Iterador 720002287 reverso. ); cout << "Output: n"; Map. erase ( Map 2. swap ( Map ); Cast para iterador constante. 24 map. Type: : const_reverse_iterator iter = Map. rbegin(); while( iter != (map. Type: : const_reverse_iterator)Map. rend() ) { cout << (*iter). first << ': ' << (*iter). second << endl; ++iter; } Busca é O(log n). cout << "Output of the name after entering the numbern" << "Number: "; long Number; Se encontrado. >> Number; cin map. Type: : const_iterator it = Map. find(Number); Uso da classe map. if(it != Map. end()) { cout << (*it). second << ' ' // O(1) << endl; } else cout << "Not found!" << endl; } 274635328: Berni 266735328: Peter 260736622: John 138373498: Thomas 135353630: William Output of the name after entering the number Number: 275734328 Paula 2008 LCG/UFRJ. All rights reserved.
Hash Map • hash_map associa objetos do tipo “key” a objetos do tipo “data”. ▪ Nenhum par de elementos possui a mesma chave. ▪ Não há ordem de percurso. ▪ Implementada por uma hash table. ◦ Há uma função de hash que gera endereços a partir de chaves. ▪ Busca em O(1). ▪ Descrição, Implementação. • hash_multimap é a versão que permite duplicatas. ▪ Descrição, Implementação. 2008 LCG/UFRJ. All rights reserved. 25
#include <ext/hash_map> #include <string> #include <iostream> 26 using namespace std; using __gnu_cxx: : hash_map; using __gun_cxx: : hash; Recebe string e // define your own hash function template <class T> class my_hash: public hash<T> { passa char*. public: // initial hash table size #define table_size 11 my_hash() {} }; size_t operator()(const string& p) const { hash<const char*> h; return h(p. c_str()); } typedef hash_map<string, my_hash<string> > map. Type; typedef map. Type: : value_type Value. Pair; int main() { map. Type Map ( table_size, my_hash <string>() ); Uso da classe hash_map. Map["ANDREW"]="Andrew"; Map["BERNI"]="Berni"; Map["JOHN"]="John"; Map. insert(Value. Pair("KAREN", "Karen")); Map. insert(Value. Pair("THOMAS", "Thomas")); Map["WILLIAM"]="William"; // insertion of Xaviera is not executed, because // the key already exists. Map. insert(Value. Pair("BERNI", "Xaviera")); 2008 LCG/UFRJ. All rights reserved.
cout << "Output: n"; 27 map. Type: : iterator iter = Map. begin(); while(iter != Map. end()) { cout << (*iter). first << ': ' << (*iter). second << endl; ++iter; } Elimina n do final de name after entering buf. cout << "Output of the keyn" << "Key: "; char buf[256]; buf[0] = '