# Chapter 21 The STL (maps and algorithms) Bjarne Chapter 21 The STL (maps and algorithms) Bjarne Stroustrup www.stroustrup.com/Programming Overview Common tasks and ideals Containers, algorithms, and iterators The simplest algorithm: find() Parameterization of algorithms Sequence containers map, set Standard algorithms

vector and list Algorithms and parameterization revisited Associative containers find_if() and function objects copy, sort, Input iterators and output iterators List of useful facilities Headers, algorithms, containers, function objects Stroustrup/Programming Nov'13 3 Basic model

A pair of iterators defines a sequence The beginning (points to the first element if any) The end (points to the one-beyond-the-last element) begin: end: An iterator is a type that supports the iterator operations of ++ Point to the next element * Get the element value == Does this iterator point to the same element as that iterator? Some iterators support more operations (e.g., --, +, and [ ]) Stroustrup/Programming Nov'13 4 Accumulate (sum the elements of a sequence) template T accumulate(In first, In last, T init) { while (first!=last) { init = init + *first; ++first;

} return init; } v: int sum = accumulate(v.begin(), v.end(), 0); 1 2 3 4 // sum becomes 10 Stroustrup/Programming Nov'13 5 Accumulate (sum the elements of a sequence) void f(vector& vd, int* p, int n) { double sum = accumulate(vd.begin(), vd.end(), 0.0); // add the elements of vd // note: the type of the 3rd argument, the initializer, determines the precision used int si = accumulate(p, p+n, 0); // sum the ints in an int (danger of overflow) // p+n means (roughly) &p[n]

long sl = accumulate(p, p+n, long(0)); // sum the ints in a long double s2 = accumulate(p, p+n, 0.0); // sum the ints in a double // popular idiom, use the variable you want the result in as the initializer: double ss = 0; ss = accumulate(vd.begin(), vd.end(), ss); // do remember the assignment } Stroustrup/Programming Nov'13 6 Accumulate (generalize: process the elements of a sequence) // we dont need to use only +, we can use any binary operation (e.g., *) // any function that updates the init value can be used: template T accumulate(In first, In last, T init, BinOp op) { while (first!=last) { init = op(init, *first); // means init op *first ++first; } return init; } Stroustrup/Programming Nov'13 7 Accumulate

// often, we need multiplication rather than addition: #include #include void f(list& ld) { double product = accumulate(ld.begin(), ld.end(), 1.0, multiplies()); // } Note: multiplies for * // multiplies is a standard library function object for multiplying Note: initializer 1.0 Stroustrup/Programming Nov'13 8 Accumulate (what if the data is part of a record?) struct Record { int units; // number of units sold double unit_price; // }; // let the update the init value function extract data from a Record element: double price(double v, const Record& r) {

return v + r.unit_price * r.units; } void f(const vector& vr) { double total = accumulate(vr.begin(), vr.end(), 0.0, price); // } Stroustrup/Programming Nov'13 9 Accumulate (what if the data is part of a record?) struct Record { int units; // number of units sold double unit_price; // }; void f(const vector& vr) { double total = accumulate(vr.begin(), vr.end(), 0.0, // use a lambda [](double v, const Record& r) { return v + r.unit_price * r.units; } ); // } // Is this clearer or less clear than the price() function? Stroustrup/Programming Nov'13 10

Inner product template T inner_product(In first, In last, In2 first2, T init) // This is the way we multiply two vectors (yielding a scalar) { while(first!=last) { init = init + (*first) * (*first2); // multiply pairs of elements and sum ++first; ++first2; } return init; } number of units * unit price 1 * 4 Stroustrup/Programming Nov'13 2 * 3 3 *

2 4 * 1 11 Inner product example // calculate the Dow-Jones industrial index: vector dow_price; // share price for each company dow_price.push_back(81.86); dow_price.push_back(34.69); dow_price.push_back(54.45); // vector dow_weight; // weight in index for each company dow_weight.push_back(5.8549); dow_weight.push_back(2.4808); dow_weight.push_back(3.8940); // double dj_index = inner_product( // multiply (price,weight) pairs and add dow_price.begin(), dow_price.end(), dow_weight.begin(), 0.0);

Stroustrup/Programming Nov'13 12 Inner product example // calculate the Dow-Jones industrial index: vector dow_price = { // share price for each company 81.86, 34.69, 54.45, // }; vector dow_weight = { // weight in index for each company 5.8549, 2.4808, 3.8940, // }; double dj_index = inner_product( // multiply (price,weight) pairs and add dow_price.begin(), dow_price.end(), dow_weight.begin(), 0.0); Stroustrup/Programming Nov'13 13 Inner product (generalize!) // we can supply our own operations for combining element values with init: template T inner_product(In first, In last, In2 first2, T init, BinOp op, BinOp2 op2) {

while(first!=last) { init = op(init, op2(*first, *first2)); ++first; ++first2; } return init; } Stroustrup/Programming Nov'13 14 Map (an associative array) For a vector, you subscript using an integer For a map, you can define the subscript to be (just about) any type Key type int main() { map words; for (string s; cin>>s; ) ++words[s]; Value type // keep (word,frequency) pairs

// note: words is subscripted by a string // words[s] returns an int& // the int values are initialized to 0 for (const auto& p : words) cout << p.first << ": " << p.second << "\n"; } Stroustrup/Programming Nov'13 15 An input for the words program (the abstract) This lecture and the next presents the STL (the containers and algorithms part of the C++ standard library). It is an extensible framework dealing with data in a C++ program. First, I present the general ideal, then the fundamental concepts, and finally examples of containers and algorithms. The key notions of sequence and iterator used to tie containers (data) together with algorithms (processing) are presented. Function objects are used to parameterize algorithms with policies. Stroustrup/Programming Nov'10 16 (data): 1 (processing): 1 (the: 1 C++: 2

First,: 1 Function: 1 I: 1 It: 1 STL: 1 The: 1 This: 1 a: 1 algorithms: 3 algorithms.: 1 an: 1 and: 5 are: 2 concepts,: 1 containers: 3 data: 1 dealing: 1 examples: 1 extensible: 1 finally: 1 framework: 1 fundamental: 1 general: 1 ideal,: 1 in: 1 is: 1 Output (word frequencies) iterator: 1

key: 1 lecture: 1 library).: 1 next: 1 notions: 1 objects: 1 of: 3 parameterize: 1 part: 1 present: 1 presented.: 1 presents: 1 program.: 1 sequence: 1 standard: 1 the: 5 then: 1 tie: 1 to: 2 together: 1 used: 2 with: 3 policies.: 1 Stroustrup/Programming Nov'13 17 Map (an associative array)

For a vector, you subscript using an integer For a map, you can define the subscript to be (just about) any type Key type int main() { map words; for (string s; cin>>s; ) ++words[s]; Value type // keep (word,frequency) pairs // note: words is subscripted by a string // words[s] returns an int& // the int values are initialized to 0 for (const auto& p : words) cout << p.first << ": " << p.second << "\n"; } Stroustrup/Programming Nov'13 18 Map

After vector, map is the most useful standard library container Maps (and/or hash tables) are the backbone of scripting languages A map is really an ordered balanced binary tree By default ordered by < (less than) For example, map fruits; Map node: fruits: Orange 99 Grape 100 Apple 7 Kiwi 2345 Key first Value second Node* left Node* right

Quince 0 Plum 8 Stroustrup/Programming Nov'13 19 Map Some implementation defined type // note the similarity to vector and list template class map { // using value_type = pair; // a map deals in (Key,Value) pairs using iterator = ???; using const_iterator = ???; iterator begin(); iterator end(); // probably a pointer to a tree node // points to first element // points to one beyond the last element

Value& operator[ ](const Key&); // get Value for Key; creates pair if // necessary, using Value( ) iterator find(const Key& k); // is there an entry for k? void erase(iterator p); // remove element pointed to by p pair insert(const value_type&); // insert new (Key,Value) pair // // the bool is false if insert failed }; Stroustrup/Programming Nov'13 20 Map example (build some maps) map dow; // Dow-Jones industrial index (symbol,price) , 03/31/2004 // http://www.djindexes.com/jsp/industrialAverages.jsp?sideMenu=true.html dow["MMM"] = 81.86; dow["AA"] = 34.69; dow["MO"] = 54.45; // map dow_weight; // dow (symbol,weight) dow_weight.insert(make_pair("MMM", 5.8549)); // just to show that a Map // really does hold pairs dow_weight.insert(make_pair("AA",2.4808));

dow_weight.insert(make_pair("MO",3.8940)); // and to show that notation matters // map dow_name; // dow (symbol,name) dow_name["MMM"] = "3M Co."; dow_name["AA"] = "Alcoa Inc."; dow_name["MO"] = "Altria Group Inc."; // Stroustrup/Programming Nov'13 21 Map example (some uses) double alcoa_price = dow["AA"]; double boeing_price = dow["BO"]; // read values from a map if (dow.find("INTC") != dow.end()) cout << "Intel is in the Dow\n"; // look in a map for an entry // iterate through a map: for (const auto& p : dow) { const string& symbol = p.first; // the "ticker" symbol cout << symbol << '\t' << p.second << '\t' << dow_name[symbol] << '\n';

} Stroustrup/Programming Nov'13 22 Map example (calculate the DJ index) double value_product( const pair& a, const pair& b) { return a.second * b.second; } // extract values and multiply double dj_index = inner_product(dow.begin(), dow.end(), dow_weight.begin(), 0.0, plus(), value_product ); Stroustrup/Programming Nov'13 // all companies in index // their weights // initial value // add (as usual)

// extract values and weights // and multiply; then sum 23 Containers and almost containers Sequence containers Associative containers array, string, stack, queue, priority_queue, bitset New C++11 standard containers map, set, multimap, multiset almost containers

vector, list, deque unordered_map (a hash table), unordered_set, For anything non-trivial, consult documentation Online SGI, RogueWave, Dinkumware Other books Stroustrup: The C++ Programming language 4th ed. (Chapters 30-33, 40.6) Austern: Generic Programming and the STL Josuttis: The C++ Standard Library Stroustrup/Programming Nov'13 24 Algorithms

An STL-style algorithm Takes one or more sequences Takes one or more operations Usually as pairs of iterators Usually as function objects Ordinary functions also work Usually reports failure by returning the end of a sequence Stroustrup/Programming Nov'13 25 Some useful standard algorithms

r=find(b,e,v) r=find_if(b,e,p) x=count(b,e,v) x=count_if(b,e,p) sort(b,e) sort(b,e,p) copy(b,e,b2) unique_copy(b,e,b2) merge(b,e,b2,e2,r) r=equal_range(b,e,v) equal(b,e,b2)

r points to the first occurrence of v in [b,e) r points to the first element x in [b,e) for which p(x) x is the number of occurrences of v in [b,e) x is the number of elements in [b,e) for which p(x) sort [b,e) using < sort [b,e) using p copy [b,e) to [b2,b2+(e-b)) there had better be enough space after b2 copy [b,e) to [b2,b2+(e-b)) but dont copy adjacent duplicates merge two sorted sequence [b2,e2) and [b,e) into [r,r+(e-b)+(e2-b2)) r is the subsequence of [b,e) with the value v (basically a binary search for v) do all elements of [b,e) and [b2,b2+(e-b)) compare equal? Stroustrup/Programming Nov'13 26 Copy example template Out copy(In first, In last, Out res) { while (first!=last) *res++ = *first++; // conventional shorthand for: // *res = *first; ++res; ++first return res; } void f(vector& vd, list& li)

{ if (vd.size() < li.size()) error("target container too small"); copy(li.begin(), li.end(), vd.begin()); // note: different container types // and different element types // (vd better have enough elements // to hold copies of lis elements) sort(vd.begin(), vd.end()); // } Stroustrup/Programming Nov'13 27 Input and output iterators // we can provide iterators for output streams ostream_iterator oo(cout); *oo = "Hello, "; ++oo; *oo = "world!\n"; // assigning to *oo is to write to cout // meaning cout << "Hello, " // get ready for next output operation // meaning cout << "world!\n" // we can provide iterators for input streams: istream_iterator ii(cin);

string s1 = *ii; ++ii; string s2 = *ii; // reading *ii is to read a string from cin // meaning cin>>s1 // get ready for the next input operation // meaning cin>>s2 Stroustrup/Programming Nov'13 28 Make a quick dictionary (using a vector) int main() { string from, to; cin >> from >> to; ifstream is(from); ofstream os(to); // get source and target file names // open input stream // open output stream istream_iterator ii(is); // make input iterator for stream istream_iterator eos; // input sentinel (defaults to EOF)

ostream_iterator oo(os,"\n"); // make output iterator for stream // append "\n" each time vector b(ii,eos); // b is a vector initialized from input sort(b.begin(),b.end()); // sort the buffer unique_copy(b.begin(),b.end(),oo); // copy buffer to output, // discard replicated values } Stroustrup/Programming Nov'13 29 An input file (the abstract) This lecture and the next presents the STL (the containers and algorithms part of the C++ standard library). It is an extensible framework dealing with data in a C++ program. First, I present the general ideal, then the fundamental concepts, and finally examples of containers and algorithms. The key notions of sequence and iterator used to tie containers (data) together with algorithms (processing) are presented. Function objects are used to parameterize algorithms with policies. Stroustrup/Programming Nov'13 30 (data) (processing)

(the C++ First, Function I It STL The This a algorithms algorithms. an and are concepts, containers data dealing examples extensible finally Framework fundamental general ideal, Part of the output in

is iterator key lecture library). next notions objects of parameterize part present presented. presents program. sequence standard the then tie to together used with policies. Stroustrup/Programming Nov'13 31

Make a quick dictionary (using a vector) We are doing a lot of work that we dont really need Why store all the duplicates? (in the vector) Why sort? Why suppress all the duplicates on output? Why not just Put each word in the right place in a dictionary as we read it? In other words: use a set Stroustrup/Programming Nov'13 32 Make a quick dictionary (using a set) int main() {

string from, to; cin >> from >> to; ifstream is(from); ofstream os(to); // get source and target file names // make input stream // make output stream istream_iterator ii(is); // make input iterator for stream istream_iterator eos; // input sentinel (defaults to EOF) ostream_iterator oo(os,"\n"); // make output iterator for stream // append "\n" each time set b(ii,eos); // b is a set initialized from input copy(b.begin(),b.end(),oo); // copy buffer to output } // simple definition: a set is a map with no values, just keys Stroustrup/Programming Nov'13 33 Set A set is really an ordered balanced binary tree

By default ordered by < For example, set fruits; set node: Key first fruits: Grape Apple Kiwi Node* left Node* right Orange Quince Plum Stroustrup/Programming Nov'13 34

copy_if() // a very useful algorithm (missing from the standard library): template Out copy_if(In first, In last, Out res, Pred p) // copy elements that fulfill the predicate { while (first!=last) { if (p(*first)) *res++ = *first; ++first; } return res; } Stroustrup/Programming Nov'13 35 copy_if() void f(const vector& v) // typical use of predicate with data // copy all elements with a value less than 6 { vector v2(v.size()); copy_if(v.begin(), v.end(), v2.begin(), [](int x) { return x<6; } ); // }

Stroustrup/Programming Nov'13 36 Some standard function objects From Binary Unary plus, minus, multiplies, divides, modulus equal_to, not_equal_to, greater, less, greater_equal, less_equal, logical_and, logical_or negate logical_not

Unary (missing, write them yourself) less_than, greater_than, less_than_or_equal, greater_than_or_equal Stroustrup/Programming Nov'13 37