680 likes | 867 Views
The STL. The heart of the STL is a collection of algorithms and data structures Each algorithm works with a large number of data structures If you create a new data structure it will work with the algorithms If you create a new algorithm is will work with the data structures
E N D
The STL • The heart of the STL is a collection of algorithms and data structures • Each algorithm works with a large number of data structures • If you create a new data structure it will work with the algorithms • If you create a new algorithm is will work with the data structures • It introduces some new concepts to allow this
Interface • How do the algorithms use the data structures? • The data structures provide a consistent way of access • We call them Iterators
Designing the Interface • An interface which is as generic as possible is wanted • It should work with arrays - since they are probably the simplest container • It should work with linked lists • It should work with trees and hash tables
Iterating through an array for (int index=0;index<length;index++) // do something with array[index] for (T* ptr = array; ptr!=&array[length];ptr++) //do something with *ptr
Iterating through a linked list for (Node *node=list.head; node!=0;node=node->next) // do something with node->value
Generic Iterating • Set current element to first element • If current element is not past the end • Do something with the current element • Set current element to the next element
STL Iterators • The key to the STL is understanding that it is designed to work with arrays • Arrays are built in to the language • You can’t inherit from them - so using OO inheritance to write generic algorithms won’t work • You can’t change the way arrays work - so you need to be compatible with them
The Basic Pointer Operations • *ptr - used to access what is pointed to • ptr++, ++ptr - used to advance to the next element • ptr == ptr2, ptr != ptr2 - used to check if two pointers point to the same element
The STL Find Algorithm template <typename Iterator, typename T> Iterator find(Iterator first, Iterator last, const T& value) { while (first!=last && *first != value) ++first; return first; } • Note that the following will work: int array[5] = {1,2,3,4,5}; cout << *(find(array,array+5,3)); //not safe!
Requirement, Concepts, Models • A concept is a set of requirements • A requirement is some operation doing a useful thing • A model, is something that fulfills a concept. • An Iterator is a concept • A pointer is a model of an Iterator.
Basic Concepts • The fundamental concepts, that seem too obvious to state • Assignable • Possible to copy values • Possible to assign new values • Default Constructable • Possible to construct an object with no arguments • T() creates an object • T t; declares a variable
Basic Concepts Continued • Equality Comparable • Possible to compare two object for equality • x == y and x != y must do so • LessThan Comparable • Possible to test if one object is less than or greater than another • x<y ,x>y, x<=y, x>=y must do so • A regular type models all the above in a consistent fashion
Input Iterator • The simplest Iterator • Three kinds of values: dereferencable, past the end, and singular • Possible to compare for equality • Possible to copy and assign • Possible to dereference to get associated value type • Possible to increment with ++i and i++
Input Iterators • That is all, for example, the following do not have to be possible • Modify the dereferenced value • Other comparison operators • Read a value more than once
Output Iterators • The other simple Iterator • Possible to copy and assign • Possible to write a value with *i = x • Possible to increment • (Again, writing twice isn’t required, testing for equality isn’t required, etc)
Using Iterators Example template <typename InputIterator, typename OutputIterator> OutputIterator copy( InputIterator first, InputIterator last, OutputIterator result) { for (;first!=last;++result,++first) *result = *first; return result; }
Iterator Implementation Example template <typename T> class ostream_iterator { public: ostream_iterator(ostream& s,const char *c=0) : os(&s),string( c ) {} ostream_iterator(const ostream_iterator& o) : os(i.os), string(i.string) {} ostream_iterator& operator=(const ostream_iterator &o) { os = i.os; string = i.string; return *this; }
ostream_iterator<T>& operator=(const T& value) { *os << value; if (string) *os << string; return *this; } ostream_iterator<T>& operator*() { return *this; } ostream_iterator<T>& operator++() { return *this; } ostream_iterator<T>& operator++(int) { return *this; } private: ostream *os; const char* string; };
Forward Iterators • Both an InputIterator and an OutputIterator • Allows multi-pass algoithms • p=q; ++q; *p = x; works
Bidirectional Iterators • Does everything a ForwardIterator does. • Also supports decrement template <typename BidirectionalIterator, typename OutputIterator > OutputIterator reverse_copy( BidirectionalIterator first, BidirectionalIterator last, OutputIterator result) { while (first != last) *(result++) = *(--last); return result; }
Random Access Iterators • Supports everything that a Bidirectional Iterators does • Supports random access • Addition and subtraction i + n and i - n • Subscripting i[n] • Subtraction of iterators i1 - i2 • Ordering i1 < i2 • Random access must be in constant time • Basically acts just like a real pointer
Ranges • Iterators are often used in ranges • A range is a start and end iterator • The start iterator is part of the range • The end iterator is not • In maths it’s [start, end) • The empty range is start==end
Containers • Containers contain elements • Container - accessed via Input Iterators • begin()andend()get iterators • Forward Container - accessed via Forward Iterators • Reversible Container - accessed via Bidirectional Iterators • rbegin() and rend() get reverse iterators • Random Access Containers - accessed via Random Access Iterators
More Container Types • There are some other Container types • Sequence • Refinement of Forward Container • Can add or delete elements at any point • member functions: insert and erase • Associative Containers • Every element has a key, by which it is looked up • Elements are added and deleted via keys
Sequence Abstractions • Front Insertion Sequence • Insertion at front in constant time • Access first element in constant time • Back Insertion Sequence • Append to end in constant time • Access last element in constant time
Associative Container Abstractions • Unique Associative Container • No two elements have the same key • Conditional insertion • Multiple Associative Container • May contain multiple elements with the same key • Simple Associative Container • The elements are their own keys • Pair Associative Container • Associates a key with another object • The value type is pair<const key, value>
Associative Container Abstractions Continued • Sorted Associative Container • Sorts elements by key in a strict weak ordering • Hashed Associative Container • Uses a hash table implementation
Vector • Simplest container, often the most efficient • Has both a size and a capacity • Inserting elements can cause reallocation • Reallocation invalidates iterators • Random Access Container • Back Insertion Sequence
Vector Usage Example #include <iostream> #include <vector> #include <algorithm> #include <string> int main() { vector<string> v; string s; while(cin>>s) v.push_back(s); copy(v.begin(),v.end(), ostream_iterator<string>(cout,"\n")); }
List • A doubly linked list • Insertion and spliciing do not invalidate iterators • Deletion only invalidates iterators at the deleted element • Reversible Container • Front Insertion Sequence • Back Insertion Sequence
List Usage Example #include <iostream> #include <list> #include <algorithm> #include <string> int main() { list<string> l; string s; while(cin>>s) l.push_front(s); copy(l.begin(), l.end(), ostream_iterator<string>(cout,"\n")); }
Deque • A double-ended queue • Insertion invalidates all iterators • Deletion from middle invalidates all iterators • Deletion at the ends invalidates iterators at the deleted element only • Random Access Container • Front Insertion Sequence • Back Insertion Sequence
Deque Usage Example #include <iostream> #include <deque> #include <algorithm> #include <string> int main() { deque<string> d; d.push_back("first"); d.push_front("second"); d.insert(d.begin()+1, "third"); d[2] = "fourth"; copy(d.begin(), d.end(), ostream_iterator<string>(cout,"\n")); }
Set • Maintains elements in sorted order • Inserting does not invalidate iterators • Deleting only invalidates iterators at the deleted element • Sorted Associative Container • Simple Associative Container • Unique Associative Container
#include <iostream> #include <set> #include <algorithm> #include <string> int main() { int prime_a[5] = {2,3,5,7,11}; int odd_a[5] = {1,3,5,7,9}; int even_a[5] = {2,4,6,8,10}; set<int> prime(prime_a,prime_a+5); set<int> odd(odd_a,odd_a+5); set<int> even(even_a,even_a+5); cout << "Union: "; set_union(prime.begin(), prime.end(), even.begin(), even.end(), ostream_iterator<int>(cout, " ")); }
Multiset • Inserting does not invalidate iterators • Deleteing only invalidates iterators at the deleted element • Sorted Associative Container • Simple Associative Container • Multiple Associative Container
Map • Inserting does not invalidate iterators • Deleting only invalidates iterators at the deleted element • Sorted Associative Container • Pair Associative Container • Unique Associative Container
Map Usage Example #include <iostream> #include <map> #include <string> int main() { map<string,int> days; days["January"] = 31; days["February"] = 28; days["March"] = 31; days["April"] = 30; cout <<"March : "<<days["March"] <<endl; }
Multimap • Sorted Associative Container • Pair Associative Container • Multiple Associative Container • Insertion does not invalidate iterators • Deletion only invalidates iterators at the deleted element
Adapters • Adapters are wrappers around a container • They work with multiple containers • They provide more specific interfaces
Stack • LIFO • Can only insert, retrieve, and delete top element • Can use any Front Insertion or Back Insertion Container • By default a deque is used • top() returns the top element • push() inserts at the top • pop() removes the top element
Queue • FIFO • Elements are added to the back, and removed from the front • Can use any Front and Back Insertion Sequence • By default a deque is used • front() retrieves element at the front • push() adds element to the back • pop() delete element at the front
Priority_queue • Can only retrieve and delete top element • The top element is always the largest • Can use any RandomAccessContainer • By default uses a vector • top() retrieves the top element • push() inserts an element • pop() removes the top element
Function Objects • It is often useful to supply a function to an algorithm • It makes the algorithm more generic • Sorting is the obvious example • In the STL we don't actually pass a function • A function object is used (which could in fact be a function)
What is a function object? • The simplest function object is a function pointer • However, an object can also be used • If operator() is overloaded the object can be used as a function • Using an object is more flexible • An object can maintain state
Types of function objects • Generators • Called with no arguments • Unary Functions • Called with one argument • Unary Predicate • A Unary Function that returns a boolean • Binary Functions • Called with two arguments • Binary Predicate • A Binary Function that returns a boolean
Basic Function Objects • Strict Weak Ordering • A Binary Predicate • f(x,x) is false • f(x,y) implies !f(y,x) • f(x,y) and f(y,z) implies f(x,z) • f(x,y) false and f(y,x) false implies x and y are equivalent • x and y equivalent, and y and z equivalent implies x and z equivalent
Basic Function Objects II • Random Number Generator • A Unary Function • f(N) returns an integer in the range [0,N) • Every integer in [0,N) will appear an equal number of times • Hash Function • A Unary Function • Maps an object to a size_t • Used by Hashed Associative Containers
STL Provided Function Objects • The STL provides a large number of Function Objects • plus, minus, multiplies, etc • logical_or,logical_and, etc • less, greater, etc
Find • Performs a linear search #include <iostream> #include <string> #include <list> #include <algorithm> int main() { list<string> l; l.push_back("bob"); l.push_back("john"); l.push_back("kate"); list<string>::iterator it= find(l.begin(),l.end(),"john"); if (it==l.end()) cout << “John not found” else cout << “John found” }