Download presentation
Presentation is loading. Please wait.
Published byErlin Muljana Modified over 6 years ago
1
John Lambert jlambert@jlambert.com
STL John Lambert
2
Copyright © 1998 J. D. Birdwell
Overview Motivation What is the STL? Where did it come from? Template review (?) Containers Iterators Algorithms Glossed-over stuff Copyright © 1998 J. D. Birdwell
3
Every line of code you don’t write is bug-free.
Why learn the STL? Every line of code you don’t write is bug-free. Copyright © 1998 J. D. Birdwell
4
Copyright © 1998 J. D. Birdwell
Perspective I’m going to blast through most of the STL The syntax can always be looked up Common sticking points will be mentioned Figuring out the right applications is trickier “Advanced” features glossed over Sneak in some “generic programming” though Eye towards you actually using it Start off by diving in… Copyright © 1998 J. D. Birdwell
5
Copyright © 1998 J. D. Birdwell
Example 1 Read in an arbitrary number of integers (n >= 1) from “numbers.txt” and display: Minimum, maximum Median Average Geometric mean ((y1 * y2 * … yn)^(1/n)) How many lines would it take you? arbitrary storage (for median), sorting, loops… Copyright © 1998 J. D. Birdwell
6
Copyright © 1998 J. D. Birdwell
Example 1: STL solution vector<int> v; copy(istream_iterator<int>(ifstream("numbers.txt")), istream_iterator<int>(), back_inserter(v)); sort(v.begin(), v.end()); cout << "min/max: " << v.front() << " " << v.back() << endl; cout << "median : " << *(v.begin() + (v.size()/2)) << endl; cout << "average: " << accumulate(v.begin(), v.end(), 0.0) / v.size() << endl; cout << "geomean: " << pow(accumulate(v.begin(),v.end(),1.0,multiplies<double>()), 1.0/v.size()) << endl; Seven (7) lines with the STL (excluding #includes) 1 line to declare data structure 1 line to read the file in 1 line to sort it 1 expression for each item to display, 4 lines Copyright © 1998 J. D. Birdwell
7
Copyright © 1998 J. D. Birdwell
Example 2 Write a program that outputs the words and the number of times it occurs in a file (sorted by word) File input, hashtable, hash function… Copyright © 1998 J. D. Birdwell
8
Copyright © 1998 J. D. Birdwell
Example 2: STL solution vector<string> v; map<string, int> m; copy(istream_iterator<string>(ifstream("words.txt")), istream_iterator<string>(), back_inserter(v)); for (vector<string>::iterator vi = v.begin(); vi != v.end(); ++vi) ++m[*vi]; for (map<string, int>::iterator mi = m.begin(); mi != m.end(); ++mi) cout << mi->first << ": " << mi->second << endl; Seven lines: 2 lines for data structures 1 lines to read in 2 lines to count 2 lines to display Copyright © 1998 J. D. Birdwell
9
Copyright © 1998 J. D. Birdwell
What is the STL? “Standard Template Library” Basic motivation: N data types, M containers, and K algorithms Possibly N *M *K implementations CountIntegerInList(IntList il, int toFind), CountIntegerInSet, CountDoubleInList, etc. STL (with C++ templates): N +M +K implementations algorithms operate over containers of types set<int> mySet; count(mySet.begin(), mySet.end(), 4); list<double> myList; count(myList.begin(), myList.end(), 3.14); Copyright © 1998 J. D. Birdwell
10
Copyright © 1998 J. D. Birdwell
Platforms STL is part of Standard C++ In Visual C++/Studio 6.0 Missing some stuff: hash_map In Visual Studio.NET / VC++ 7.0 Still some issues G++ 3.0: dunno Stlport.org Free std C++ implementation (including iostreams), some nice features/performance Copyright © 1998 J. D. Birdwell
11
Copyright © 1998 J. D. Birdwell
Where did it come from? Alex Stepanov “In 1976, still back in the USSR, I got a very serious case of food poisoning from eating raw fish.” “While in the hospital, in the state of delirium, I suddenly realized that the ability to add numbers in parallel depends on the fact that addition is associative.” (Huh?) “Putting it simply, STL is the result of a bacterial infection.” (That I can understand.) Copyright © 1998 J. D. Birdwell
12
Copyright © 1998 J. D. Birdwell
STL overview Fundamentally, the STL defines algorithms that operate over a range in a container Our order: Containers Iterators (ranges) Algorithms Copyright © 1998 J. D. Birdwell
13
Copyright © 1998 J. D. Birdwell
Containers Lists vector, list, deque Adaptors queue, priority_queue, stack Associative map, multimap, set, multiset hash_{above} Copyright © 1998 J. D. Birdwell
14
Copyright © 1998 J. D. Birdwell
vector<T> #include <vector> A dynamic array: random-access, grows Array-indexing syntax: vector<int> v(10); v[0] = 4; Copyright © 1998 J. D. Birdwell
15
Copyright © 1998 J. D. Birdwell
vector<T> Constructors vector<T>() vector<T>(size_t num_elements) vector<T>(size_t num, T init) Properties v.empty() // true if v has 0 elements v.size() // number of elements v.capacity() // number of elements v can hold before allocating more memory (cap ! nec. = size) Copyright © 1998 J. D. Birdwell
16
Copyright © 1998 J. D. Birdwell
vector<T> Adding elements v.push_back(42); // increases size v[0] = 31; // only ok if v.size() >= 1 v.insert(iter before, T val) // skipped v.insert(iter before, iter start, iter end) // skipped Accessing elements v.at(i) // reference, range checked! v[i] // reference, not range checked v.front() // reference to first element v.back() // reference to last element v.back() = 4; // legal if size > 0 Copyright © 1998 J. D. Birdwell
17
Copyright © 1998 J. D. Birdwell
vector<T> Removing elements v.pop_back(): removes last element, returns nothing v.clear(): removes everything v.erase(iterator i) // skipped v.erase(iter start, iter end) // skipped Copyright © 1998 J. D. Birdwell
18
Copyright © 1998 J. D. Birdwell
vector<T> Time: constant time insertion and removal of elements at the end linear time insertion and removal of elements at the beginning or in the middle. The “standard” container Copyright © 1998 J. D. Birdwell
19
vector<T> example
vector<char> v; for (int i = 0; i < 10; ++i) v.push_back('A' + i); cout << v[0] << v.back() << endl; // AJ v.pop_back(); // doesn't return anything cout << v.size() << v.back() << endl; // 9I for (size_t i = 0; i < v.size(); ++i) cout << v[i]; // ABCDEFGHI (no J) cout << endl; Copyright © 1998 J. D. Birdwell
20
Forward reference: Iterators
v.begin() and v.end() return iterators Like pointers: arithmetic (++, --) and dereferencing (*) for (vector<char>::iterator i = v.begin(); i != v.end(); ++i) cout << *i; // ABCDEFGHI (no J) Copyright © 1998 J. D. Birdwell
21
Copyright © 1998 J. D. Birdwell
list<T> Bidirectional, linear list Sequential access only (not L[52]) Constructors list<T>() list<T>(size_t num_elements) list<T>(size_t num, T init) Properties l.empty() // true if l has 0 elements l.size() // number of elements Copyright © 1998 J. D. Birdwell
22
Copyright © 1998 J. D. Birdwell
list<T> Adding elements l.push_back(43); l.push_front(31); l.insert(iter b, iter s, iter s) // and others, skipped Accessing elements l.front() // T & l.back() // T & l.begin() // list<T>::iterator l.end() // list<T>::iterator Copyright © 1998 J. D. Birdwell
23
Copyright © 1998 J. D. Birdwell
list<T> Removing elements l.pop_back() // returns nothing l.pop_front() // returns nothing l.erase(iterator i) l.erase(iter start, iter end) Time Amortized constant time insertion and removal of elements at the beginning or the end, or in the middle [because you pass an iterator] Copyright © 1998 J. D. Birdwell
24
Copyright © 1998 J. D. Birdwell
list<T> Other operations l.sort(), l.sort(CompFn) // sorts in place, can’t use normal sort function (why?) l.splice(iter b, list<T>& grab_from) Copyright © 1998 J. D. Birdwell
25
Copyright © 1998 J. D. Birdwell
list<T> Example: list<char> l; for (int i = 0; i < 4; ++i) { l.push_front(i + 'A'); l.push_back(i + 'A'); } for (list<char>::iterator i = l.begin(); i != l.end(); ++i) cout << *i; // DCBAABCD Copyright © 1998 J. D. Birdwell
26
Copyright © 1998 J. D. Birdwell
Step back! Notice anything? A lot of the functions (c.begin(), c.end()) are the same! So, write a “generic” display function… Now displaying a “supported” container is 1 line! template<typename Container> void display(Container & c) { for(Container::iterator i = c.begin(); i != c.end(); ++i) cout << *i << " "; cout << endl; } Wait for it, btw… Copyright © 1998 J. D. Birdwell
27
Copyright © 1998 J. D. Birdwell
deque<T> Double-ended queue Random access List: no d[i] Vector: no push_front Good for adding/removing at beginning Copyright © 1998 J. D. Birdwell
28
deque<T>: readers/writers
deque<char> d; srand(1337); for (int i = 0; i < N; ++i) { if (rand() % 2) // add a random letter to the back d.push_back((rand() % 26) + 'A'); else if (d.size()) // take the one in the front d.pop_front(); if (d.size()) display(d); } cout << d.size() << " elements left!" << endl; cout << "final: "; display(d); Readers/Writers, sorta Copyright © 1998 J. D. Birdwell
29
deque<T> example output
N N B B B I B I F B I F F B I F F K I F F K I F F K H F F K H F K H K H K H X K H X K K H X K F H X K F X K F Copyright © 1998 J. D. Birdwell
30
Copyright © 1998 J. D. Birdwell
deque<T>: time Constant time insertion and removal of elements at the beginning/end of the sequence Linear time insertion and removal of elements in the middle Copyright © 1998 J. D. Birdwell
31
Copyright © 1998 J. D. Birdwell
queue<T> First-in, first-out (FIFO) only front(), back(), push(), pop() No q[i] No iterators (need to write display_queue) An “adaptor”: uses a deque internally Could use a list (ads/disads): queue<T,list<T> > Same example as deque Copyright © 1998 J. D. Birdwell
32
queue<T> example
queue<char> q; srand(1337); for (int i = 0; i < N; ++i) { if (rand() % 2) // add a random letter to the back q.push((rand() % 26) + 'A'); // was d.push_back( else if (q.size()) // take the one in the front q.pop(); // was d.pop_front() if (q.size()) display_queue(q); } cout << q.size() << " elements left!" << endl; cout << "final: "; display_queue(q); Same output as before! Copyright © 1998 J. D. Birdwell
33
Copyright © 1998 J. D. Birdwell
display_queue Why couldn’t we use display<Container>? No iterators in queue! VC++ doesn’t have “partial template specialization”, so we can’t do: template<typename T, typename C> void display(const queue<T, C>& c) We need a new function... Q will expand to queue<T> or queue<T, list<T> > or whatever’s needed template<typename Q> void display_queue(const Q & q) { Q qc(q); // make copy while (!qc.empty()) { cout << qc.front() << " "; qc.pop(); } cout << endl; Copyright © 1998 J. D. Birdwell
34
priority_queue<T>
“Sorted” queue pop(), push(T t), size(), top() (instead of front()) Can take a comparison object in ctor Handwaving, we’ll come back to this Generally use bool operator<(T a, T b) Example: job scheduling A job has a name, priority, and user High (valued) priority jobs go first If tie, then lowest user goes first Copyright © 1998 J. D. Birdwell
35
Copyright © 1998 J. D. Birdwell
Job struct definition struct Job { string name; int user; int pri; Job(string n, int u, int p): name(n), user(u), pri(p){} }; Copyright © 1998 J. D. Birdwell
36
Copyright © 1998 J. D. Birdwell
Job helper operators ostream& operator<<(ostream& o, Job j) { o << j.name << "\tuser=" << j.user << ", pri=" << j.pri; return o; } bool operator<(Job j1, Job j2) { return (j1.pri < j2.pri) || (j1.pri == j2.pri && j1.user>j2.user); Copyright © 1998 J. D. Birdwell
37
Actual priority_queue<T> code
priority_queue<Job> pq; pq.push(Job("printer", 1, 5)); pq.push(Job("gcc", 200, 4)); pq.push(Job("kernel", 1, 10)); pq.push(Job("nfs", 1, 7)); pq.push(Job("irc", 800, 4)); pq.push(Job("ftpd", 1, 2)); pq.push(Job("pine", 100, 4)); while (!pq.empty()) // display { cout << pq.top() << endl; // uses operator<< pq.pop(); } Copyright © 1998 J. D. Birdwell
38
Copyright © 1998 J. D. Birdwell
Priority queue output kernel user=1, pri=10 nfs user=1, pri=7 printer user=1, pri=5 pine user=100, pri=4 gcc user=200, pri=4 irc user=800, pri=4 ftpd user=1, pri=2 Copyright © 1998 J. D. Birdwell
39
Copyright © 1998 J. D. Birdwell
stack<T> Last in, first out (LIFO) push(), pop(), top(), size() Example: palindrome push letters on to stack pop them off and store in a different string if the strings are equal, it’s a palindrome terrible approach, but I needed an example Copyright © 1998 J. D. Birdwell
40
Copyright © 1998 J. D. Birdwell
stack<T> // returns true if input is a palindrome bool is_palindrome_naive(string input) { stack<char> st; for(int i = 0; i < input.size(); ++i) st.push(input[i]); // add to stack string back = ""; while (!st.empty()) { back += st.top(); st.pop(); } return (back == input); // this is where I cry Copyright © 1998 J. D. Birdwell
41
Copyright © 1998 J. D. Birdwell
Review (so far) vector: dynamic array, random access list: linked list, one-directional access deque: double-ended queue, random access queue: like deque, but just push, pop, front, back priority_queue: “sorted” queue, only push, pop, top stack: LIFO, push, pop, top Deep breath: only going to get cooler Copyright © 1998 J. D. Birdwell
42
[hash_]map, [hash_]multimap
A map is an “associative container” Given one value, will find another map<string, int> is a map from strings to int’s maps are 1:1, multimap are 1:n map, multimap are logarithmic when inserting/deleting Needs to maintain sortedness hash_map, hash_multimap are amortized constant time Not sorted (“hashed”) Copyright © 1998 J. D. Birdwell
43
Copyright © 1998 J. D. Birdwell
Mmm… pairs… pair<KeyType, ValueType> is used with maps Can use pairs outside of (inside) maps, too Can create pair<K,V> objects with make_pair(k, v): pair<string, int> si("foo", 42); si = make_pair("bar", 24); Copyright © 1998 J. D. Birdwell
44
Generically output pairs?
template <typename T1, typename T2> ostream& operator<<(ostream& o, const pair<typename T1, typename T2> p) { o << "(" << p.first << ", " << p.second << ")"; return o;} cout << make_pair( make_pair("str", 31), make_pair(Job("kernel", 1, 3), 9) ) << endl; Output: ((str, 31), (kernel user=1, pri=3, 9)) Bonus: typeid(T1).name() is the data type’s name (double, int, etc.) Copyright © 1998 J. D. Birdwell
45
Copyright © 1998 J. D. Birdwell
Map functions m.insert(make_pair(key, value)); // inserts m.count(key); // times occurs (0, 1) m.erase(key); // removes it m[key] = value; // inserts it into the table m[key] //retrieves or creates a “default” for it m.begin(), m.end() // iterators Copyright © 1998 J. D. Birdwell
46
Copyright © 1998 J. D. Birdwell
Map example typedef pair<string, int> dorm_location; map<string, dorm_location> people; people.insert(make_pair("jrl7", dorm_location("staley", 810))); cout << people["jrl7"] << endl; // (staley, 810) cout << people["JRL7"] << endl; // (, 0) people["jrl7"] = dorm_location("pierce", 411); for (map<string, dorm_location>::iterator p = people.begin(); p != people.end(); ++p) cout << "Name: " << p->first << ": " << p->second << endl; // Name: JRL7: (, 0) // Name: jrl7: (pierce, 411) Note that just cout’ing people["JRL7"] inserted it into the map! We also overwrote my staley address with pierce p->first == (*p).first (C++ arrow notation) Copyright © 1998 J. D. Birdwell
47
Copyright © 1998 J. D. Birdwell
Multimap Like map, but 1:n instead Introduces new function: mm.upper_bound(key) is an iterator that comes after all the elements specified No more [ ] indexing, either mm.count(key) will return count (0, 1, .. N) Copyright © 1998 J. D. Birdwell
48
Copyright © 1998 J. D. Birdwell
Multimap example Output: 314 430 345 multimap<string, int> mm; mm.insert(make_pair("PSCL", 102)); mm.insert(make_pair("EECS", 314)); mm.insert(make_pair("EECS", 430)); mm.insert(make_pair("EECS", 345)); mm.insert(make_pair("PSCL", 101)); multimap<string, int>::iterator i = mm.find("EECS"); if (i != mm.end()) // we found some EECS do { cout << i->second << endl; ++i; } while (i != mm.upper_bound("EECS")); Copyright © 1998 J. D. Birdwell
49
Multimap example (continued)
// display all; could use display(mm)! for (i = mm.begin(); i != mm.end(); ) { const multimap<string, int>::iterator j = mm.upper_bound(i->first); cout << i->first<<' ' << mm.count( i->first) << ":"; do { cout << i->second << " "; ++i; } while(i != j && i != mm.end()); cout << endl; } Output: EECS 3: PSCL 2: Copyright © 1998 J. D. Birdwell
50
Copyright © 1998 J. D. Birdwell
Step back Now we’ve seen like 6 containers They’re all pretty similar We go through them with iterators similarly Code “patterns” Learn once, apply to others Copyright © 1998 J. D. Birdwell
51
Copyright © 1998 J. D. Birdwell
Set Unique values, sorted Somewhat like a map, except that the key = value Copyright © 1998 J. D. Birdwell
52
Copyright © 1998 J. D. Birdwell
Set example (using mm) set<string> depts; for (multimap<string, int>::iterator i = mm.begin(); i != mm.end(); ++i) depts.insert(i->first); display(depts); display(mm); EECS PSCL (EECS, 314) (EECS, 430) (EECS, 345) (PSCL, 102) (PSCL, 101) Copyright © 1998 J. D. Birdwell
53
Copyright © 1998 J. D. Birdwell
Multiset More than one key for a lot of items “An auto-sorted list” Counts quickly Copyright © 1998 J. D. Birdwell
54
Copyright © 1998 J. D. Birdwell
Multiset multiset<char> grades; grades.insert('A'); grades.insert('C'); grades.insert('D'); grades.insert('C'); grades.insert('F'); grades.insert('D'); grades.insert('B'); grades.insert('I'); display(grades); cout << grades.count('D') << endl; Output A B C C D D F I 2 Copyright © 1998 J. D. Birdwell
55
Copyright © 1998 J. D. Birdwell
Hash_{…} There are hash_map, hash_multimap, hash_set, hash_multiset Basically, these are constant time insert/delete instead of log time They don’t maintain sortedness Me: reduced running time from 10 min to 5 min Copyright © 1998 J. D. Birdwell
56
Copyright © 1998 J. D. Birdwell
Hash performance Fill with 100,000 random elements Lookup 200,000 random elements Same random seed map: fill s map: lookups s hash_map: fill s hash_map: lookups s So, if you don’t need order, go with hash_map Copyright © 1998 J. D. Birdwell
57
Classes in associative cont.
Can always put your classes in associative containers Must have a default (no-arg) constructor Must have global bool operator<(T a, T b) Might need == as well Don’t put pointers in! set<string*> ss; ss.insert(new string("foo")); cout << ss.size() << endl; // outputs 2! Copyright © 1998 J. D. Birdwell
58
Copyright © 1998 J. D. Birdwell
Summary map: 1:1, sorted, m[k] = v multimap: 1:n, sorted, mm.insert(make_pair(k,v)) set: unique elements, sorted multiset: multiple keys allowed, sorted hash_: faster but not sorted Copyright © 1998 J. D. Birdwell
59
Copyright © 1998 J. D. Birdwell
Iterators Touched on earlier An iterator is like a pointer You can increment to it to go to the “next” element You can [sometimes] subtract or add N You can dereference it Different kinds of iterators Most useful when combined with algorithms Copyright © 1998 J. D. Birdwell
60
Copyright © 1998 J. D. Birdwell
Iterators Copyright © 1998 J. D. Birdwell
61
Copyright © 1998 J. D. Birdwell
Iterators c.begin() = start c.end() = 1 past the last element Never dereference end! (*c.end() is bad!) Why? Makes loops simpler. Prefer ++i because i++ makes a temporary object and returns it, incrementing later. Copyright © 1998 J. D. Birdwell
62
Copyright © 1998 J. D. Birdwell
Different kinds Technically: random access (i += 3; --i; ++i) bidirectional (++i, --i), store/retreive forward (++i), store/retrieve input (++i) retrieve output (++o) store But, writing code directly using iterators hurts a lot Copyright © 1998 J. D. Birdwell
63
Copyright © 1998 J. D. Birdwell
Practical iterators iterator “Standard”, goes from beginning to end c.begin(), c.end() const_iterator Like iterator, but changes can’t be made (prefer!) c.begin() and c.end() are overloaded so you can use them to assign their result to a const_iterator reverse_iterator Goes from the end to the beginning with same semantics as iterator Generally, c.rbegin() and c.rend() list, vector, deque, map, multimap, set, multiset, hash_, string Copyright © 1998 J. D. Birdwell
64
Copyright © 1998 J. D. Birdwell
Iterator example vector<int> v; for (int k = 0; k < 7; ++k) v.push_back(k); display(v); // for(vector<int>::iterator i = v.begin(); i != v.end(); ++i) *i = *i + 3; // add three to content display(v); // for(vector<int>::const_iterator ci = v.begin(); ci != v.end(); ++ci) cout << *ci << ' ';// *ci = *ci - 3; won't compile cout << endl;// for (vector<int>::reverse_iterator ri = v.rbegin(); ri != v.rend(); ++ri) { *ri = *ri - 3; cout << *ri << ' ';} cout << endl; // Copyright © 1998 J. D. Birdwell
65
Copyright © 1998 J. D. Birdwell
“Insert” iterators back_inserter(Container) returns an iterator that calls push_back when assigned to front_inserter(Container) returns an iterator that calls push_front inserter(Container, where) is “generalized” inserter, works for sets, maps, etc. Example in a second or two Copyright © 1998 J. D. Birdwell
66
Array/iterator parallelism:
int A[] = {1, 4, 2, 8, 5, 7}; const int N = sizeof(A) / sizeof(int); for(int* i = A; i != A + N; ++i) cout << *i << ' '; Copyright © 1998 J. D. Birdwell
67
Copyright © 1998 J. D. Birdwell
Algorithms AKA: finally, the cool part Basically, the STL provides 70 algorithms of general interest Pretty much all of them take in iterators and return iterators Hardest to wrap your mind around Not going to talk about function objects Copyright © 1998 J. D. Birdwell
68
General algorithm categories
Copying Searching unsorted sequences Searching sorted sequences Replacing/removing elements Reordering Sorting Merging sorted sequences Set operations Heap operations Minimum/maximum Permutations Transforming and generating Miscellanous Numeric Copyright © 1998 J. D. Birdwell
69
Copyright © 1998 J. D. Birdwell
All algorithms adjacent_find, binary_search, copy, copy_backward, count, count_if, equal, equal_range, fill, fill_n, find, find_end, find_first_of, find_if, for_each, generate, generate_n, includes, inplace_merge, iter_swap, lexicographical_compare, lower_bound, make_heap, max, max_element, merge, min, min_element, mismatch, next_permutation, nth_element, partial_sort, partial_sort_copy, partition, pop_heap, prev_permutation, push_heap, random_shuffle, remove, remove_copy, remove_copy_if, remove_if, replace, replace_copy, replace_copy_if, replace_if, reverse, reverse_copy, rotate, rotate_copy, search, search_n, set_difference, set_intersection, set_symmetric_difference, set_union, sort, sort_heap, stable_partition, stable_sort, swap, swap_ranges, transform, unique, unique_copy, upper_bound accumulate, adjacent_difference, inner_product, partial_sum Copyright © 1998 J. D. Birdwell
70
Copyright © 1998 J. D. Birdwell
Our algorithms copy, find, remove, unique, reverse, sort, min/max_element, count, accumulate, for_each, transform, equal Writing your own Copyright © 1998 J. D. Birdwell
71
Copyright © 1998 J. D. Birdwell
copy(b, e, Dest) vector<int> w, v; w.push_back(42); w.push_back(31); w.push_back(1); v.resize(w.size()); // needed copy(w.begin(), w.end(), v.begin()); vector<int> c; copy(w.begin(), w.end(), back_inserter(c)); // calls c.push_back deque<int> d; copy(w.begin(), w.end(), front_inserter(d)); // calls d.push_front display(v); // display(c); // display(d); // (b/c added to front) Copyright © 1998 J. D. Birdwell
72
copy + istream iterators
An istream iterator reads from an istream (file, console, etc.) until an eof is received Hopefully this makes sense now: vector<int> v; copy(istream_iterator<int>(ifstream("numbers.txt")), istream_iterator<int>(), back_inserter(v)); Note that the “end” iterator is istream_iterator<int>(); a special instance which indicates the EOF Copyright © 1998 J. D. Birdwell
73
copy + ostream iterators
Same goes for ostream_iterators: copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); Now, we can rewrite display in two lines, with no loops: template<typename Container> void display(const Container & c, string sep = " ") { copy(c.begin(), c.end(), ostream_iterator<Container::value_type>(cout, sep.c_str())); cout << endl; } Copyright © 1998 J. D. Birdwell
74
Copyright © 1998 J. D. Birdwell
i = find(b, e, val) Returns an iterator (or e if not found) if (find(v.begin(), v.end(), 31) != v.end()) cout << "Found 31." << endl; Copyright © 1998 J. D. Birdwell
75
Copyright © 1998 J. D. Birdwell
ne = remove(b, e, val) Doesn’t actually modify the end point: returns the new end point remove_copy(b, e, Dest, val) will remove val while copying to Dest v.clear(); for(int i = 0; i < 10; ++i) v.push_back(i); vector<int> vc; remove_copy(v.begin(), v.end(), back_inserter(vc), 4); display(vc); // vector<int>::const_iterator e = remove(v.begin(), v.end(), 4); display(v); // “extra 9” for (vector<int>::const_iterator vi = v.begin(); vi != e; ++vi) // not v.end() cout << *vi << ' '; cout << endl; // Copyright © 1998 J. D. Birdwell
76
Copyright © 1998 J. D. Birdwell
sort(b, e) Sorts a range; needs random access iterators N log N, average and worst case sort(v.begin(), v.end()); Will raise a compile time error if not supported Can sort normal arrays this way, too int A[] = {1, 4, 2, 8, 5, 7}; const int N = sizeof(A) / sizeof(int); sort(A, A + N); Copyright © 1998 J. D. Birdwell
77
Copyright © 1998 J. D. Birdwell
ne = unique(b, e) Doesn’t actually modify the end point unique_copy Removes “consecutive duplicate elements” Sort first if you want a “real unique” list Just like remove Linear Copyright © 1998 J. D. Birdwell
78
Copyright © 1998 J. D. Birdwell
reverse(b, e) Bidirectional iterators Reverses the range in-place Linear for(int i = 0; i < 10; ++i) v.push_back(i); display(v); // reverse(v.begin(), v.end()); display(v); // Copyright © 1998 J. D. Birdwell
79
Copyright © 1998 J. D. Birdwell
min/max_element(b,e) An iterator to the minimum/maximum element in a range (e if range is empty) (*min_element(..) is value) Doesn’t need to be sorted list<int> l; l.push_back(4); l.push_front(12); l.push_back(1); l.push_front(2); l.push_back(7); display(l); // cout << *min_element(l.begin(), l.end()) << endl; // 1 cout << *max_element(l.begin(), l.end()) << endl; // 12 Copyright © 1998 J. D. Birdwell
80
Copyright © 1998 J. D. Birdwell
count(b, e, V) Counts occurances of V in range b, e count_if(b, e, Func): bool iscomma(char c) { return c == ','; } string s = "(X,Y) or [X,Y]?"; cout << count_if(s.begin(), s.end(), iscomma) << endl; Outputs 2 Copyright © 1998 J. D. Birdwell
81
accumulate(b, e, initial)
in <numeric> Adds (+) up the values in the range b, e Iinitial is used if it’s an empty range As long as operator+ is defined, we’re good You can pass in a binary function to use instead of + (beyond scope) vector<string> vs; vs.push_back("This"); vs.push_back("Talk"); vs.push_back("Is"); vs.push_back("Way"); vs.push_back("Too"); vs.push_back("Long"); cout << accumulate(vs.begin(), vs.end(), string("")) << endl; // ThisTalkIsWayTooLong Copyright © 1998 J. D. Birdwell
82
Copyright © 1998 J. D. Birdwell
for_each(b, e, op) Call op(*i) for each i in range b, e; magical void display_backwards(string s) { // strings have reverse iterators copy(s.rbegin(), s.rend(), ostream_iterator<char>(cout)); } for_each(vs.begin(), vs.end(), display_backwards); // sihTklaTsIyaWooTgnoL Copyright © 1998 J. D. Birdwell
83
Copyright © 1998 J. D. Birdwell
for_each(b, e, op) Using “function objects”, you can do some neat stuff void truncate_word(string s, int len) { cout << s.substr(0, len); } for_each(vs.begin(), vs.end(), bind2nd(ptr_fun(truncate_word), 2)); // ThTaIsWaToLo Copyright © 1998 J. D. Birdwell
84
Copyright © 1998 J. D. Birdwell
transform My favorite; probably the most powerful algorithm Two forms: transform(b, e, out, UnaryFunc): Applies UnaryFunc to b, e and stores result in out string s = "hello"; string upcase, upcasebackwards; transform(s.begin(), s.end(), back_inserter(upcase), toupper); // reverse and upper case in one line transform(s.rbegin(), s.rend(), back_inserter(upcasebackwards), toupper); cout << upcase << " " << upcasebackwards << endl; // HELLO OLLEH // straight to screen transform(s.rbegin(), s.rend(), ostream_iterator<char>(cout), toupper); // OLLEH cout << endl; Copyright © 1998 J. D. Birdwell
85
Copyright © 1998 J. D. Birdwell
transform transform(Argument 1 beginning, Arg 1 end, Argument 2 beginning, output, BinaryFunction); typedef pair<double, double> point; point midpoint(point p1, point p2) { return point((p1.first + p2.first)/2.0, (p1.second + p2.second)/2.0); } vector<point> v1, v2; v1.push_back(point(0.0, 3.1)); v1.push_back(point(7.3, 8.1)); v1.push_back(point(9.1, -2.89)); v2.push_back(point(4.3, 9.3)); v2.push_back(point(1.3, 9.1)); v2.push_back(point(8.3, -3.1)); display(v1); // (0, 3.1) (7.3, 8.1) (9.1, -2.89) display(v2); // (4.3, 9.3) (1.3, 9.1) (8.3, -3.1) transform(v1.begin(), v1.end(), v2.begin(), ostream_iterator<point>(cout, " "), midpoint); // (2.15, 6.2) (4.3, 8.6) (8.7, ) Copyright © 1998 J. D. Birdwell
86
Copyright © 1998 J. D. Birdwell
bool equal(b, e, b2); Returns true if the ranges are identical Can rewrite is_palindrome: return equal(input.begin(), input.end(), input.rbegin()); “the string going forwards is the same as going backwards” Better: no space overhead Copyright © 1998 J. D. Birdwell
87
Writing own algorithms
Poor example… template<typename Iter, typename Val> void add_to_each(Iter b, Iter e, Val v) { while (b != e) { *b = *b + v; ++b; } vector<int> v; v.push_back(0); v.push_back(1); v.push_back(2); add_to_each(v.begin(), v.end(), 4); display(v); // 4 5 6 Copyright © 1998 J. D. Birdwell
88
Copyright © 1998 J. D. Birdwell
Review Let’s go back over the Examples at the beginning of the presentation Problem 1: Read in a list of numbers, min/max, avg, geo mean, median Problem 2: Read in a list of words and output the number of times each word occurs Copyright © 1998 J. D. Birdwell
89
Copyright © 1998 J. D. Birdwell
Example 1: STL solution vector<int> v; copy(istream_iterator<int>(ifstream("numbers.txt")), istream_iterator<int>(), back_inserter(v)); sort(v.begin(), v.end()); cout << "min/max: " << v.front() << " " << v.back() << endl; // could have used min/max_element but list already sorted cout << "median : " << *(v.begin() + (v.size()/2)) << endl; cout << "average: " << accumulate(v.begin(), v.end(), 0.0) / v.size() << endl; cout << "geomean: " << pow(accumulate(v.begin(),v.end(),1.0,multiplies<double>()), 1.0/v.size()) << endl; Seven (7) lines with the STL (excluding #includes) 1 line to declare data structure 1 line to read the file in 1 line to sort it 1 expression for each item to display, 4 lines Copyright © 1998 J. D. Birdwell
90
Copyright © 1998 J. D. Birdwell
Example 2: STL solution vector<string> v; map<string, int> m; copy(istream_iterator<string>(ifstream("words.txt")), istream_iterator<string>(), back_inserter(v)); for (vector<string>::iterator vi = v.begin(); vi != v.end(); ++vi) ++m[*vi]; for (map<string, int>::iterator mi = m.begin(); mi != m.end(); ++mi) cout << mi->first << ": " << mi->second << endl; Seven lines: 2 lines for data structures 1 lines to read in 2 lines to count 2 lines to display Copyright © 1998 J. D. Birdwell
91
Copyright © 1998 J. D. Birdwell
Conclusion The STL has everything Let the compiler do the work for you Saves time and lines of code Next steps: Buy a good book on STL Schildt’s STL Programming from the Ground Up Use it on your homeworks/personal projects Learn about function objects Didn’t have time to cover them; another talk?? Copyright © 1998 J. D. Birdwell
92
Copyright © 1998 J. D. Birdwell
Resources Books Schildt – “STL Programming from the Ground Up” *** Schildt – “C/C++ Programmers Reference” URLs MSDN Google: sgi stl <container or algorithm> Copyright © 1998 J. D. Birdwell
93
Copyright © 1998 J. D. Birdwell
Miscellaneous STLPort has a runtime “debug mode” #define _STLP_DEBUG 1 list<int> l1(array1, array1 + 3); list<int> l2(array2, array2 + 2); l1.erase(l2.begin()); _debug.h:70 STL error : Container doesn't own the iterator Also: copy(v1.begin(), v2.end(), v2.begin()); l1.erase(l1.end()); Copyright © 1998 J. D. Birdwell
94
Containers with pointers
Need to write a custom comparison object Can’t use operator< on non-class objects struct stringpointerless: public binary_function<string*, string*, bool> { bool operator()(string* s, string* t) { return *s < *t; }}; // could have been more generic! set<string*, stringpointerless > ss; (works now) Copyright © 1998 J. D. Birdwell
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.