2008 LCG/UFRJ. All rights reserved. 1 Standard Template Library STL Claudio Esperança Paulo Roma Cavalcanti
2008 LCG/UFRJ. All rights reserved. 2 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. 3 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.SGI Ou então a nossa implementação de um subconjunto da STL.STL Na nossa implementação, cada classe tem o prefixoutl (não havia namespace ainda). Se a variável de compilação USE_STL estiver definida, o prefixo será suprimido, cgcUtil:: será substituído por std::, e o compilador usará a STL nativa então.
2008 LCG/UFRJ. All rights reserved. 4 Estrutura da STL A STL oferece: Containers (recipientes).Containers Iterators (iteradores).Iterators Algorithms (algoritmos).Algorithms Recipientes servem para armazenar dados e podem ser classificados como: Seqüências de dadosSeqüências Recipientes associativos para pares de objetos (chave, dado).Recipientes associativos Adaptadores que provêem um subconjunto da funcionalidade de um recipiente. Pilhas, filas, filas de prioridade.Pilhasfilasfilas de prioridade
2008 LCG/UFRJ. All rights reserved. 5 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. 6 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. 7 Imprimindo elementos de um vetor #include using namespace std; /** função objeto. *Insere T em um stream de saída. *Substitui passar ponteiro para função de C. */ template struct print : public unary_function { print(ostream& out) : os(out), count(0) {} void operator() (T x) { os << x << ' '; ++count; } ostream& os; int count; }; int main() { int A[] = {1, 4, 2, 8, 5, 7}; const int N = sizeof(A) / sizeof(int); print P = for_each(A, A + N, print (cout)); cout << endl << P.count << " objects printed." << endl; return 1; } objects printed. Calcula o tamanho de A Dois iteradores Redefine operador ( ) Construtor Guarda número de elementos impressos Chama print() para cada elemento de A
2008 LCG/UFRJ. All rights reserved. 8 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.Descrição implementação
2008 LCG/UFRJ. All rights reserved. 9 Uso da classe vector. #include using namespace std; using __gnu_cxx::is_sorted; int main() { vector V; V.push_back(20); V.push_back(30); V.push_back(-1); cout << "V: \n"; copy(V.begin(), V.end(), ostream_iterator (cout, " ")); stable_sort (V.begin(), V.end()); cout << "\nV: sorted\n"; copy(V.begin(), V.end(), ostream_iterator (cout, " ")); cout << "\nV: is sorted? "; cout << is_sorted ( V.begin(), V.end() ) << "\n"; } V: V: sorted V: is sorted? 1 Insere no final de V. Insere V no stream de saída Ordena V com merge sort. Verifica se V está ordenado.
2008 LCG/UFRJ. All rights reserved. 10 Função copy. /**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) * first where to start copying. last where to end copying. result where to copy. result + (last-first). */ template inline OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result) { for( InputIterator itr = first; itr != last; ++itr, ++result ) { *result = *itr; } return result; } Apenas percorre o recipiente de entrada. E atribui ao recipiente da saída. Derivados da mesma classe base.
2008 LCG/UFRJ. All rights reserved. 11 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.Descrição implementação
2008 LCG/UFRJ. All rights reserved. 12 Uso da classe deque. #include using namespace std; int main() { deque Q; Q.push_back(3); Q.push_front(1); Q.insert(Q.begin() + 1, 2); Q[2] = 0; copy(Q.begin(), Q.end(), ostream_iterator (cout, " ")); cout << "\n"; // The values that are printed are Q.insert(Q.begin() + 1, (size_t)3, 5); Q.push_front(7); Q.push_front(8); Q.push_front(9); Insere 5 três vezes após a primeira posição.
2008 LCG/UFRJ. All rights reserved. 13 Uso da classe deque. copy(Q.begin(), Q.end(), ostream_iterator (cout, " ")); cout << "\n"; deque P = Q; copy(Q.begin(), Q.end(), ostream_iterator (cout, " ")); cout << "\n"; P.resize ( 18, 88 ); P.push_front ( 99 ); P.push_front ( 98 ); copy(P.begin(), P.end(), ostream_iterator (cout, " ")); P.erase ( P.begin(), P.begin()+2 ); cout << "\n"; cout << P.back(); cout << "\n"; cout << P.front(); cout << "\n"; cout << *P.begin(); cout << "\n"; } Redimensiona P completando com 88 no final. Remove os dois primeiros elementos de P. Último elemento de P Primeiro elemento de P
2008 LCG/UFRJ. All rights reserved. 14 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.DescriçãoImplementação
2008 LCG/UFRJ. All rights reserved. 15 Uso da classe list. #include using namespace std; int main() { list L; L.push_back(0); L.push_front(1); L.insert(++L.begin(), 2); copy(L.begin(), L.end(), ostream_iterator (cout, " ")); cout << "\n"; list M ( L ); L.splice ( ++++L.begin(), M ); copy(L.begin(), L.end(), ostream_iterator (cout, " ")); cout << \n; copy(M.begin(), M.end(), ostream_iterator (cout, " ")); } Insere 0 no final de L Insere 1 no início de L. Insere 2 após a primeira posição. Move elementos de M para L. M está vazia.
2008 LCG/UFRJ. All rights reserved. 16 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.DescriçãoImplementação
2008 LCG/UFRJ. All rights reserved. 17 Uso da classe string. #include using namespace std; int main () { //test constructors string str0; cout << "empty constructor: " << str0 << endl; cout << "str0 size = " << str0.size() << endl; string str1("hellow world!"); // cout << "const char constructor: " << str1 << endl; cout << "data = " << str1.data() << endl; cout << "size = " << str1.size() << endl; cout << "length = " << str1.length() << endl; cout << "capacity = " << str1.capacity() << endl; cout << "max_size = " << str1.max_size() << endl; // empty cout << "str0 empty = " << str0.empty() << endl; cout << "str1 empty = " << str1.empty() << endl; empty constructor: str0 size = 0 const char constructor: hellow world! data = hellow world! size = 13 length = 13 capacity = 13 max_size = 13 str0 empty = 1 str1 empty = 0 Capacidade da string sem ter de realocar. Tamanho máximo que uma string pode ter. Comprimento atual da string O mesmo que length.
2008 LCG/UFRJ. All rights reserved. 18 Uso da classe string. string str2(str1); cout << copy constructor: " << str2 << endl; string str3(str1, 4, 6); cout << "string&, pos, npos, str3 constructor: " << str3 << endl; string str4("hellow word!", 6); cout << "char[], npos, str4 constructor: " << str4 << endl; string str5(12, 'h'); cout << n, char str5 constructor: " << str5 << endl; cout << "str5 size = " << str5.size() << endl; // swap str5.swap(str1); cout << "swap str1 and str5" << endl; cout << "str1 = " << str1 << endl; cout << "str5 = " << str5 << endl; } copy constructor: hellow world! string&, pos, npos, str3 constructor: ow wor char[], npos, str4 constructor: hellow n, char str5 constructor: hhhhhhhhhhhh str5 size = 12 swap str1 and str5 str1 = hhhhhhhhhhhh str5 = hellow world! Troca o conteúdo de str5 por str1.
2008 LCG/UFRJ. All rights reserved. 19 Set set é uma coleção ordenada de objetos do tipokey 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.DescriçãoImplementação multiset é a versão que permite duplicatas. Descrição, Implementação.DescriçãoImplementação
2008 LCG/UFRJ. All rights reserved. 20 Uso da classe set. #include using namespace std; /// função objeto. Compara duas seqüências de caracteres. struct ltstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 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"}; set A(a, a + N); set B(b, b + N); set C; Retorna se s 1 é lexicograficamente menor que s 2 Construtor a partir de dois iteradores
2008 LCG/UFRJ. All rights reserved. 21 Uso da classe set. cout << "Set A: "; copy(A.begin(), A.end(), ostream_iterator (cout, " ")); cout << endl; cout << "Set B: "; copy(B.begin(), B.end(), ostream_iterator (cout, " ")); cout << endl; cout << "Union: "; set_union(A.begin(), A.end(), B.begin(), B.end(), ostream_iterator (cout, " "), ltstr()); cout << endl; cout << "Intersection: "; set_intersection(A.begin(), A.end(), B.begin(), B.end(), ostream_iterator (cout, " "), ltstr()); cout << endl; 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 (cout, " ")); cout << endl; } 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 A B. A – B.Insere o resultado em C.
2008 LCG/UFRJ. All rights reserved. 22 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.DescriçãoImplementação multimap é a versão que permite duplicatas. Descrição, Implementação.DescriçãoImplementação
2008 LCG/UFRJ. All rights reserved. 23 Uso da classe map. #include using namespace std; typedef map mapType; typedef mapType::value_type ValuePair; int main() { mapType Map; Map[ ] = "Andrew"; Map[ ] = "Berni"; Map[ ] = "Ulisses"; Map[ ] = "Paulo"; Map[ ] = "Pedro"; Map[ ] = "Peter"; Map[ ] = "Paula"; Map[ ] = "Paulos"; Map.insert(ValuePair( , "John")); Map.insert(ValuePair( , "Karen")); Map.insert(ValuePair( , "Thomas")); Map.insert(ValuePair( , "William")); // insertion of Xaviera is not executed, because // the key already exists. Map.insert(ValuePair( , "Xaviera")); mapType Map2 ( Map.begin(), Map.end() ); cout << "equality operator " << (Map2 == Map) << endl; Duas formas de inserção Chave e dado.Cria um par (chave,dado). equality operator 1 Output: :Ulisses :Andrew :Karen :Pedro :Paulo :Paulos :Paula Ordem decrescente.
2008 LCG/UFRJ. All rights reserved. 24 Uso da classe map. cout << "Output:\n"; Map.erase ( ); Map2.swap ( Map ); mapType::const_reverse_iterator iter = Map.rbegin(); while( iter != (mapType::const_reverse_iterator)Map.rend() ) { cout << (*iter).first << ':' << (*iter).second << endl; ++iter; } cout << "Output of the name after entering the number\n" << "Number: "; long Number; cin >> Number; mapType::const_iterator it = Map.find(Number); if(it != Map.end()) { cout << (*it).second << ' ' // O(1) << endl; } else cout << "Not found!" << endl; } Se encontrado. Busca é O(log n). Iterador reverso. Cast para iterador constante :Berni :Peter :John :Thomas :William Output of the name after entering the number Number: Paula
2008 LCG/UFRJ. All rights reserved. 25 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.DescriçãoImplementação hash_multimap é a versão que permite duplicatas. Descrição, Implementação.DescriçãoImplementação
2008 LCG/UFRJ. All rights reserved. 26 Uso da classe hash_map. #include using namespace std; using __gnu_cxx::hash_map; using __gun_cxx::hash; // initial hash table size #define table_size 11 // define your own hash function template class my_hash: public hash { public: my_hash() {} size_t operator()(const string& p) const { hash h; return h(p.c_str()); } }; typedef hash_map > mapType; typedef mapType::value_type ValuePair; int main() { mapType Map ( table_size, my_hash () ); Map["ANDREW"]="Andrew"; Map["BERNI"]="Berni"; Map["JOHN"]="John"; Map.insert(ValuePair("KAREN", "Karen")); Map.insert(ValuePair("THOMAS", "Thomas")); Map["WILLIAM"]="William"; // insertion of Xaviera is not executed, because // the key already exists. Map.insert(ValuePair("BERNI", "Xaviera")); Recebe string e passa char*.
2008 LCG/UFRJ. All rights reserved. 27 Uso da classe hash_map. cout << "Output:\n"; mapType::iterator iter = Map.begin(); while(iter != Map.end()) { cout << (*iter).first << ':' << (*iter).second << endl; ++iter; } cout << "Output of the name after entering the key\n" << "Key: "; char buf[256]; buf[0] = '\0'; fgets ( buf, 256, stdin ); if ( buf[strlen(buf)-1]=='\n' ) buf[strlen(buf)-1] = '\0'; string key ( buf ); iter = Map.find(key); if(iter != Map.end()) { cout << (*iter).second << ' ' << Map[key] << endl; } else cout << "Not found!" << endl; } Elimina \n do final de buf. Busca é O(1) Output: JOHN:John BERNI:Berni KAREN:Karen ANDREW:Andrew THOMAS:Thomas WILLIAN:Willian Output of the name after entering the key Key: KAREN Karen Não há ordem.